2012-06-04 29 views
14

Widziałem tylko przykłady do ustawienia metody __repr__ w definicjach klas. Czy jest możliwa zmiana __repr__ dla funkcji w ich definicjach lub po ich zdefiniowaniu?Czy można zmienić funkcję repr w pythonie?

Mam próbowali bez powodzenia ...

>>> def f(): 
    pass 
>>> f 
<function f at 0x1026730c8> 
>>> f.__repr__ = lambda: '<New repr>' 
>>> f 
<function __main__.f> 

Odpowiedz

14

Tak, jeśli chcesz zrezygnować z funkcji, która w rzeczywistości jest funkcją.

pierwsze, zdefiniowanie klasy dla naszego nowego typu:

import functools 
class reprwrapper(object): 
    def __init__(self, repr, func): 
     self._repr = repr 
     self._func = func 
     functools.update_wrapper(self, func) 
    def __call__(self, *args, **kw): 
     return self._func(*args, **kw) 
    def __repr__(self): 
     return self._repr(self._func) 

Dodaj w funkcji dekorator:

def withrepr(reprfun): 
    def _wrap(func): 
     return reprwrapper(reprfun, func) 
    return _wrap 

A teraz możemy zdefiniować repr wraz z funkcją:

@withrepr(lambda x: "<Func: %s>" % x.__name__) 
def mul42(y): 
    return y*42 

Teraz repr(mul42) produkuje '<Func: mul42>'

+3

Proszę użyć 'functools.wraps' dla dekoratorów, aby zaktualizować nazwę i docstring funkcji dekorowanych. – schlamar

+1

Problem polega na tym, że 'print mul42 .__ name__' spowodowałby wzrost AttributeError, który nie jest oczekiwany dla funkcji. Więc byłoby to: 'return wraps (func) (reprwrapper (reprfun, func))', aby to naprawić. – schlamar

+1

@ ms4py W tym przypadku myślę, że 'update_wrapper' jest nieco bardziej odpowiedni/bezpośredni. Zmodyfikowałem klasę opakowania tak, aby robiła to w swoim konstruktorze. W ten sposób aktualizacja dzieje się nawet wtedy, gdy używasz klasy bezpośrednio, zamiast korzystania z dekoratora 'withrepr'. – kwatford

5

Nie, ponieważ repr(f) odbywa jak type(f).__repr__(f) zamiast.

3

W tym celu należy zmienić funkcję __repr__ dla danej klasy, która w tym przypadku jest wbudowaną klasą funkcji (types.FunctionType). Ponieważ w Pythonie nie można edytować wbudowanych klas, tylko je podklasować, nie można.

Jednakże istnieją dwa podejścia można śledzić:

  1. Wrap niektóre funkcje jak kwatford zasugerował
  2. Stwórz swój własny protokół reprezentacji z własnym funkcji repr. Na przykład można zdefiniować funkcję myrepr, która najpierw szuka metod, których nie można dodać do klasy funkcji, ale można ją dodać do poszczególnych obiektów funkcji zgodnie z sugestią (a także do niestandardowych klas i obiektów), a następnie domyślnie repr, jeśli nie znaleziono __myrepr__. Ewentualna realizacja tego będzie:

    def myrepr(x): 
        try: 
        x.__myrepr__ 
        except AttributeError: 
        return repr(x) 
        else: 
        return x.__myrepr__() 
    

    Następnie można zdefiniować __myrepr__ metody i korzystać z funkcji myrepr. Możesz również wykonać __builtins__.repr = myrepr, aby ustawić domyślną funkcję repr i nadal używać repr. Takie podejście zakończyłoby się robieniem dokładnie tego, czego chcesz, ale edycja __builtins__ nie zawsze jest pożądana.