Comment puis-je obtenir la classe qui a défini une méthode en Python?
Je voudrais que l'exemple suivant imprime "__main__.FooClass
":
class FooClass:
def foo_method(self):
print "foo"
class BarClass(FooClass):
pass
bar = BarClass()
print get_class_that_defined_method(bar.foo_method)
import inspect
def get_class_that_defined_method(meth):
for cls in inspect.getmro(meth.im_class):
if meth.__in cls.__dict__:
return cls
return None
Merci Sr2222 d'avoir souligné que je manquais le point ...
Voici l'approche corrigée qui ressemble à celle d'Alex mais ne nécessite rien d'importer. Je ne pense pas que ce soit une amélioration, à moins qu'il n'y ait une énorme hiérarchie de classes héritées car cette approche s'arrête dès que la classe de définition est trouvée, au lieu de renvoyer tout l'héritage comme le fait getmro
. Comme nous l'avons dit, il s'agit d'un très scénario peu probable.
def get_class_that_defined_method(method):
method_name = method.__name__
if method.__self__:
classes = [method.__self__.__class__]
else:
#unbound method
classes = [method.im_class]
while classes:
c = classes.pop()
if method_name in c.__dict__:
return c
else:
classes = list(c.__bases__) + classes
return None
Et l'exemple:
>>> class A(object):
... def test(self): pass
>>> class B(A): pass
>>> class C(B): pass
>>> class D(A):
... def test(self): print 1
>>> class E(D,C): pass
>>> get_class_that_defined_method(A().test)
<class '__main__.A'>
>>> get_class_that_defined_method(A.test)
<class '__main__.A'>
>>> get_class_that_defined_method(B.test)
<class '__main__.A'>
>>> get_class_that_defined_method(C.test)
<class '__main__.A'>
>>> get_class_that_defined_method(D.test)
<class '__main__.D'>
>>> get_class_that_defined_method(E().test)
<class '__main__.D'>
>>> get_class_that_defined_method(E.test)
<class '__main__.D'>
>>> E().test()
1
La solution Alex renvoie les mêmes résultats. Tant que l'approche Alex peut être utilisée, je l'utiliserais à la place de celle-ci.
Je ne sais pas pourquoi personne n'a jamais soulevé cette question ou pourquoi la réponse du haut a 50 votes positifs quand c'est lent, mais vous pouvez également faire ce qui suit:
def get_class_that_defined_method(meth):
return meth.im_class.__name__
Pour python 3 je crois que cela a changé et vous devrez examiner .__qualname__
.
J'ai commencé à faire quelque chose de similaire, l'idée était de vérifier chaque fois qu'une méthode dans une classe de base avait été implémentée ou non dans une sous-classe. Il s'est avéré que je l'ai fait à l'origine, je n'ai pas pu détecter quand une classe intermédiaire implémentait réellement la méthode.
Ma solution pour cela était assez simple en fait; définir une méthode attribut et tester sa présence ultérieurement. Voici une simplification de l'ensemble:
class A():
def method(self):
pass
method._orig = None # This attribute will be gone once the method is implemented
def run_method(self, *args, **kwargs):
if hasattr(self.method, '_orig'):
raise Exception('method not implemented')
self.method(*args, **kwargs)
class B(A):
pass
class C(B):
def method(self):
pass
class D(C):
pass
B().run_method() # ==> Raises Exception: method not implemented
C().run_method() # OK
D().run_method() # OK
MISE À JOUR: En fait, appelez method()
à partir de run_method()
(n'est-ce pas l'esprit?) Et faites-lui passer tous les arguments non modifiés à la méthode.
P.S .: Cette réponse ne répond pas directement à la question. À mon humble avis, il y a deux raisons pour lesquelles on voudrait savoir quelle classe a défini une méthode; la première consiste à pointer du doigt une classe dans le code de débogage (comme dans la gestion des exceptions), et la seconde consiste à déterminer si la méthode a été réimplémentée (où méthode est un stub destiné à être implémenté par le programmeur). Cette réponse résout ce deuxième cas d'une manière différente.
Dans Python 3, si vous avez besoin de l'objet de classe réel, vous pouvez le faire:
import sys
f = Foo.my_function
vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]] # Gets Foo object
Si la fonction peut appartenir à une classe imbriquée, vous devez itérer comme suit:
f = Foo.Bar.my_function
vals = vars(sys.modules[f.__module__])
for attr in f.__qualname__.split('.'):
vals = vals[attr]
# vals is now the class Foo.Bar