2013-05-21 14 views
6

Próbuję się upewnić, że wykonanie help() w Pythonie 2.7 REPL wyświetla __doc__ dla funkcji, która została opakowana w functools.partial. Aktualnie działająca help() na "funkcji" functools.partial wyświetla __doc__ z klasy functools.partial, a nie mojej funkcji zapakowanej __doc__. Czy istnieje sposób, aby to osiągnąć?Pozwól, aby pomoc() działała na obiekt funkcji częściowej

Rozważmy następujące callables:

def foo(a): 
    """My function""" 
    pass 

partial_foo = functools.partial(foo, 2) 

Running help(foo) spowoduje pokazując foo.__doc__. Jednak uruchomienie help(partial_foo) powoduje, że __doc__ z Partial object.

Moim pierwszym podejściem było użycie functools.update_wrapper, które poprawnie zastępuje obiekt częściowy __doc__ z foo.__doc__. Jednak to nie rozwiązuje problemu z powodu tego, jak pydoc.

mam zbadane kod pydoc, a problem wydaje się, że partial_foo jest rzeczywiście Partial object nie typowa funkcja/wymagalne, zobacz this question uzyskać więcej informacji o tym szczegółowo.

Domyślnie, pydoc wyświetli __doc__ typu obiektu, a nie instancji, jeśli obiekt, który został przekazany, zostanie określony jako klasa przez inspect.isclass. Zobacz render_doc function, aby uzyskać więcej informacji na temat samego kodu.

Tak więc, w moim scenariuszu powyżej pydoc wyświetla pomoc typu: functools.partial NOT __doc__ z mojej instancji .

Czy mimo to, aby zmienić moje wezwanie do help() lub functools.partial instancji, który jest przekazywany do help() tak, że będzie wyświetlać __doc__ instancji, nie wpisać?

+0

Nie sądzę, aby to obejść; nie ma tu haków, które moglibyśmy złapać. –

Odpowiedz

2

znalazłem całkiem hacky sposób to zrobić. Pisałem następującą funkcję przesłonić __builtins__.help funkcję:

def partialhelper(object=None): 
    if isinstance(object, functools.partial): 
     return pydoc.help(object.func) 
    else: 
     # Preserve the ability to go into interactive help if user calls 
     # help() with no arguments. 
     if object is None: 
      return pydoc.help() 
     else: 
      return pydoc.help(object) 

Następnie wystarczy zastąpić go w REPL z:

__builtins__.help = partialhelper 

To działa i nie wydaje się mieć żadnych poważnych wad, jeszcze. Jednak nie ma sposobu, aby powyższa naiwna implementacja obsługi nadal pokazywała obiekty. Jest to wszystko lub nic, ale prawdopodobnie może dołączyć atrybut do funkcji zawijanej (oryginalnej), aby wskazać, czy oryginalny plik __doc__ powinien zostać wyświetlony. Jednak w moim scenariuszu nigdy nie chcę tego robić.

Uwaga powyższe NIE działa, gdy używany jest IPython i embed functionality.Dzieje się tak dlatego, że IPython bezpośrednio ustawia przestrzeń nazw powłoki z odniesieniami do "prawdziwego" __builtin__, zobacz informacje o tym, dlaczego jest to code i stara mailing list.

Po przeprowadzeniu dochodzenia istnieje inny sposób na zhackowanie tego do IPython. Musimy zastąpić klasę site._Helper, która jest używana przez IPython do explicitly setup the help system. Poniższy kod będzie zrobić tylko, że gdy wezwany przed IPython.embed:

import site 
site._Helper.__call__ = lambda self, *args, **kwargs: partialhelper(*args, **kwargs) 

Czy są jakieś inne downsides mi tu brakuje?

+0

Warto również zauważyć, że NIE będzie działać w IPython. Na pewno istnieje sposób obejścia tego, ale IPython nie ma '__builtins __. Help', nawet jeśli funkcja' help() 'jest dostępna w globalnej przestrzeni nazw. Propozycje? –

+0

Zobacz aktualizacje dla "poprawki" dla IPython. –

0

jak wdrożyć własne?

def partial_foo(*args): 
    """ some doc string """ 
    return foo(*((2)+args)) 
nie

idealne rozwiązanie, ale jeśli naprawdę chcesz, to podejrzewam, że jest to jedyny sposób na to

+0

To zadziała, ale niezbyt dobrze dla mojego scenariusza. Mam dużą listę funkcji, które wszystkie muszą mieć ten sam argument domyślnie do czegoś w czasie wykonywania. Tak więc wymagałoby to wielu takich funkcji opakowania. –

Powiązane problemy