Posso vedere cosa fa un decoratore Python al mio codice?
-
20-12-2019 - |
Domanda
C'è un modo per vedere cosa ha fatto l'applicazione di un decoratore Python con una funzione a cui l'ho applicato.Ad esempio se ho
class A(object):
@property
def something(self):
return 0
.
Mi piacerebbe vedere quale è il codice che viene eseguito per something
in realtà sembra.C'è un modo per farlo?
Soluzione
Un decoratore non produce codice; Un decoratore è davvero solo zucchero sintattico:
@property
def something(self):
return 42
.
è davvero interpretato come:
def something(self):
return 42
something = property(something)
.
E.G. L'espressione che segue il segno @
viene valutata e il risultato è chiamato, passando nella funzione o classe seguendo la linea @
. Qualunque sia il decoratore, quindi restituisce sostituisce l'oggetto originale.
Per scopi di introspezione, la linea @
è non mantenuta; Dovresti analizzare il codice sorgente stesso per scoprire tutti i decoratori presenti. Un decoratore non è obbligato a restituire un nuovo oggetto; Puoi restituire l'oggetto originale inalterato e non puoi, con l'introspezione, conosci la differenza.
La tua migliore scommessa è tornare alla fonte del decoratore e semplicemente leggere il codice. Il decoratore property
è implementato in c, ma il descrittore Howtowow contiene un Python Implementazione che fa la stessa cosa:
class Property(object):
"Emulate PyProperty_Type() in Objects/descrobject.c"
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
if doc is None and fget is not None:
doc = fget.__doc__
self.__doc__ = doc
def __get__(self, obj, objtype=None):
if obj is None:
return self
if self.fget is None:
raise AttributeError("unreadable attribute")
return self.fget(obj)
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError("can't set attribute")
self.fset(obj, value)
def __delete__(self, obj):
if self.fdel is None:
raise AttributeError("can't delete attribute")
self.fdel(obj)
def getter(self, fget):
return type(self)(fget, self.fset, self.fdel, self.__doc__)
def setter(self, fset):
return type(self)(self.fget, fset, self.fdel, self.__doc__)
def deleter(self, fdel):
return type(self)(self.fget, self.fset, fdel, self.__doc__)
.