Come faccio a deduco la classe a cui appartiene un @staticmethod?
-
09-09-2019 - |
Domanda
Sto cercando di implementare la funzione infer_class
che, dato un metodo, capisce la classe a cui appartiene il metodo.
Finora ho qualcosa di simile:
import inspect
def infer_class(f):
if inspect.ismethod(f):
return f.im_self if f.im_class == type else f.im_class
# elif ... what about staticmethod-s?
else:
raise TypeError("Can't infer the class of %r" % f)
Non funziona per @ staticmethod-s, perché non ero in grado di trovare un modo per raggiungere questo obiettivo.
Qualche suggerimento?
Ecco infer_class
in azione:
>>> class Wolf(object):
... @classmethod
... def huff(cls, a, b, c):
... pass
... def snarl(self):
... pass
... @staticmethod
... def puff(k,l, m):
... pass
...
>>> print infer_class(Wolf.huff)
<class '__main__.Wolf'>
>>> print infer_class(Wolf().huff)
<class '__main__.Wolf'>
>>> print infer_class(Wolf.snarl)
<class '__main__.Wolf'>
>>> print infer_class(Wolf().snarl)
<class '__main__.Wolf'>
>>> print infer_class(Wolf.puff)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in infer_class
TypeError: Can't infer the class of <function puff at ...>
Soluzione
Questo perché staticmethods in realtà non sono metodi. Il descrittore staticmethod restituisce la funzione originale come è. Non v'è alcun modo per ottenere la classe attraverso il quale si accedeva alla funzione. Ma non c'è una vera ragione per usare staticmethods per i metodi in ogni caso, sempre utilizzare classmethods.
L'unico uso che ho trovato per staticmethods è quello di memorizzare oggetti funzione come attributi di classe e non hanno li trasformano in metodi.
Altri suggerimenti
Ho problemi portando a me stesso di realtà consiglia questo, ma sembra di lavorare per i casi semplici, almeno:
import inspect
def crack_staticmethod(sm):
"""
Returns (class, attribute name) for `sm` if `sm` is a
@staticmethod.
"""
mod = inspect.getmodule(sm)
for classname in dir(mod):
cls = getattr(mod, classname, None)
if cls is not None:
try:
ca = inspect.classify_class_attrs(cls)
for attribute in ca:
o = attribute.object
if isinstance(o, staticmethod) and getattr(cls, sm.__name__) == sm:
return (cls, sm.__name__)
except AttributeError:
pass