Domanda

Come posso ottenere la classe che ha definito un metodo in Python?

vorrei il seguente esempio per stampare "__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)
È stato utile?

Soluzione

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

Altri suggerimenti

Grazie per aver ricordato Sr2222 mi mancava il punto di ...

Ecco l'approccio corretto, che è proprio come Alex, ma non richiede di importare nulla. Io non credo che sia un miglioramento, però, a meno che non ci sia una grande gerarchia di classi ereditate da questo approccio si ferma non appena la classe che definisce si trova, invece di restituire l'intera eredità come getmro fa. Come detto, questa è una molto scenario improbabile.

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

E l'esempio:

>>> 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

soluzione Alex restituisce gli stessi risultati. Finché approccio Alex può essere utilizzato, io lo uso al posto di questo.

Non so il motivo per cui nessuno ha mai portato questo in su o perché la risposta superiore dispone di 50 upvotes quando è lento come l'inferno, ma è anche possibile effettuare le seguenti operazioni:

def get_class_that_defined_method(meth):
    return meth.im_class.__name__

Per Python 3 Credo che questo è cambiato e avrete bisogno di guardare in .__qualname__.

ho iniziato a fare qualcosa di un po 'simile, in fondo l'idea stava controllando ogni volta che un metodo in una classe di base era stata attuata o meno in una classe secondaria. Si è rivelato il modo in cui ho fatto inizialmente non ho potuto rilevare quando una classe intermedia è stato effettivamente attuando il metodo.

La mia soluzione per è stato abbastanza semplice in realtà; l'impostazione di un metodo attributo e testando la presenza tardi. Ecco una semplificazione di tutta la faccenda:

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

UPDATE:. In realtà chiamare method() da run_method() (? Non è che lo spirito) e farlo passare tutti gli argomenti non modificati al metodo

P.S .: Questa risposta non risponde direttamente alla domanda. IMHO ci sono due ragioni vorrebbe sapere quale classe definito un metodo; primo è quello di indicare le barrette ad una classe nel codice debug (come nella gestione delle eccezioni), e il secondo è quello di determinare se il metodo è stato re-implementato (dove metodo è uno stub pensato per essere implementato dal programmatore). Questa risposta risolve questo secondo caso in modo diverso.

In Python 3, se avete bisogno l'oggetto classe reale che si può fare:

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

Se la funzione potrebbe appartenere a una classe annidata si avrebbe bisogno di iterare nel seguente modo:

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top