2012-06-04 12 views
14

Ho visto solo esempi per l'impostazione del metodo __repr__ nelle definizioni di classe. È possibile modificare lo __repr__ per le funzioni nelle rispettive definizioni o dopo averle definite?È possibile modificare la replica di una funzione in python?

ho tentato senza successo ...

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

risposta

14

Sì, se si è disposti a rinunciare alla funzione in realtà è una funzione.

In primo luogo, definire una classe per il nostro nuovo tipo:

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) 

Aggiungi in una funzione decoratore:

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

e ora possiamo definire il repr con la funzione:

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

Ora repr(mul42) produce '<Func: mul42>'

+3

Utilizzare 'functools.wraps' per i decoratori per aggiornare il nome e la docstring delle funzioni decorate. – schlamar

+1

Il problema è che 'print mul42 .__ name__' genererebbe un AttributeError che non è previsto per una funzione. Quindi sarebbe: 'return wraps (func) (reprwrapper (reprfun, func))' per risolvere il problema. – schlamar

+1

@ ms4py In questo caso penso che 'update_wrapper' sia leggermente più appropriato/diretto. Ho modificato la classe wrapper in modo che faccia ciò nel suo costruttore. In questo modo l'aggiornamento avviene anche se si usa direttamente la classe invece di usare il decoratore 'withrepr'. – kwatford

5

No, perché repr(f) è fatto come type(f).__repr__(f) invece.

3

Per fare ciò, è necessario modificare la funzione __repr__ per la classe data, che in questo caso è la classe funzione incorporata (types.FunctionType). Dato che in Python non è possibile modificare le classi integrate, solo la sottoclasse, non è possibile.

Tuttavia, ci sono due approcci si potrebbe seguire:

  1. Wrap alcune funzioni come kwatford suggerito
  2. Crea il tuo protocollo di rappresentazione con la propria funzione repr. Ad esempio, è possibile definire una funzione myrepr che cerca prima i metodi __myrepr__, che non è possibile aggiungere alla classe di funzione, ma è possibile aggiungerla ai singoli oggetti funzione come suggerito (nonché le classi e gli oggetti personalizzati), quindi il valore predefinito è repr se __myrepr__ non è stato trovato. Una possibile implementazione per questo sarebbe:

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

    allora si potrebbe definire __myrepr__ metodi e utilizzare la funzione myrepr. In alternativa, puoi anche fare __builtins__.repr = myrepr per rendere la tua funzione predefinita repr e continuare a utilizzare repr. Questo approccio finirebbe per fare esattamente quello che vuoi, anche se la modifica di __builtins__ potrebbe non essere sempre auspicabile.

Problemi correlati