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)
python
python-2.6
python-datamodel
Jesse Aldridge
la source
la source
Réponses:
import inspect def get_class_that_defined_method(meth): for cls in inspect.getmro(meth.im_class): if meth.__name__ in cls.__dict__: return cls return None
la source
__dict__
! Parfois__slots__
est utilisé. Il est probablement préférable de l'utilisergetattr
pour tester si la méthode est dans la classe.Python 3
, veuillez vous référer à cette réponse .'function' object has no attribute 'im_class'
Merci Sr2222 d'avoir signalé que je manquais le point ...
Voici l'approche corrigée qui ressemble à celle d'Alex mais qui ne nécessite rien d'importer. Je ne pense pas que ce soit une amélioration cependant, à moins qu'il 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
getmro
fait. Comme dit, c'est un scénario très improbable.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.
la source
Cls().meth.__self__
vous donne simplement l'instance deCls
qui est liée à cette instance spécifique demeth
. C'est analogue àCls().meth.im_class
. Si vous avezclass SCls(Cls)
,SCls().meth.__self__
vous obtiendrez uneSCls
instance, pas uneCls
instance. Ce que l'OP veut, c'est obtenirCls
, ce qui semble être uniquement disponible en marchant sur le MRO comme le fait @Alex Martelli.Je ne sais pas pourquoi personne n'a jamais soulevé cela ou pourquoi la première réponse a 50 votes positifs alors que c'est lent comme l'enfer, mais vous pouvez également faire ce qui suit:
def get_class_that_defined_method(meth): return meth.im_class.__name__
Pour python 3, je pense que cela a changé et vous devrez vous pencher sur
.__qualname__
.la source
Dans Python 3, si vous avez besoin de l'objet de classe réel, vous pouvez 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('.')[:-1]: vals = vals[attr] # vals is now the class Foo.Bar
la source
J'ai commencé à faire quelque chose de similaire, essentiellement l'idée était de vérifier chaque fois qu'une méthode d'une classe de base avait été implémentée ou non dans une sous-classe. Il s'est avéré comme je l'ai fait à l'origine que je ne pouvais pas détecter quand une classe intermédiaire implémentait réellement la méthode.
Ma solution de contournement était en fait assez simple; définir un attribut de méthode 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()
derun_method()
(n'est-ce pas l'esprit?) Et faites-lui passer tous les arguments non modifiés à la méthode.PS: 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; le premier est de pointer du doigt une classe dans le code de débogage (comme dans la gestion des exceptions), et le second est de déterminer si la méthode a été réimplémentée (où method 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.
la source
Python 3
Résolu le problème d'une manière très simple:
str(bar.foo_method).split(" ", 3)[-2]
Cela donne
'FooClass.foo_method'
Fractionner sur le point pour obtenir la classe et le nom de la fonction séparément
la source