Question

Comment puis-je obtenir la classe qui a défini une méthode en Python?

Je veux l'exemple suivant pour imprimer "__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)
Était-ce utile?

La solution

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

Autres conseils

Merci d'avoir signalé Sr2222 je manque le point ...

Voici l'approche corrigé qui est tout comme Alex, mais ne nécessite pas d'importer quoi que ce soit. Je ne pense pas que ce soit une amélioration mais, à moins qu'il ya une énorme hiérarchie de classes héritées que cette approche s'arrête dès que la classe de définition se trouve, au lieu de retourner toute l'héritage que getmro fait. Comme l'a dit, cela 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

solution Alex retourne les mêmes résultats. Tant que l'approche Alex peut être utilisé, je l'utiliser à la place de celui-ci.

Je ne sais pas pourquoi personne n'a jamais soulevé cette question ou pourquoi la réponse supérieure a 50 upvotes quand il est lent comme l'enfer, mais vous pouvez aussi 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 aurez besoin de regarder dans .__qualname__.

J'ai commencé à faire quelque chose un peu similaire, au fond l'idée vérifiait chaque fois qu'une méthode dans une classe de base a été mis en œuvre ou non dans une sous-classe. Tourné sur la façon dont je l'ai fait à l'origine je ne pouvais pas détecter quand une classe intermédiaire a été mise en oeuvre réelle de la méthode.

Ma solution car il était assez simple en fait; définir une méthode attribut et tester sa présence plus tard. Voici une simplification de la chose:

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 appel method() de run_method() (? Est-ce pas l'esprit) et ont 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; première consiste à diriger des doigts à une classe dans le code de débogage (par exemple dans le traitement des exceptions), et la deuxième consiste à déterminer si le procédé a été re-mis en oeuvre (où la méthode est une ébauche destinée à être mise en oeuvre par le programmeur). Cette réponse résout ce second cas, d'une manière différente.

En Python 3, si vous avez besoin de l'objet de classe réelle que vous pouvez faire:

import sys
f = Foo.my_function
vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]]  # Gets Foo object

Si la fonction pourrait 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top