Pregunta

¿Cómo puedo obtener la clase que define un método en Python?

Me gustaría tener el siguiente ejemplo para imprimir "__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)
¿Fue útil?

Solución

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

Otros consejos

Sr2222 Gracias por señalar que faltaba el punto ...

Este es el enfoque corregida que es igual que la de Alex, pero no requiere importar nada. No creo que sea una mejora, sin embargo, a menos que haya una enorme jerarquía de clases heredadas ya que este enfoque se detiene tan pronto como se encuentra la definición de la clase, en lugar de devolver toda la herencia como getmro hace. Como se ha dicho, este es un muy escenario poco 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

Y el ejemplo:

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

solución Alex devuelve los mismos resultados. Mientras Alex enfoque se puede utilizar, lo usaría en lugar de éste.

No sé por qué no se ha llevado nunca este arriba o por qué la respuesta superior tiene 50 upvotes cuando es lento como el infierno, pero también se puede hacer lo siguiente:

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

En Python 3 Creo que esto ha cambiado y que necesita para mirar en .__qualname__.

empecé a hacer algo un tanto similar, básicamente, la idea era el registro cada vez que un método en una clase base se ha aplicado o no en una subclase. Salido de la forma que hice originalmente no podía detectar cuando una clase intermedia fue en realidad la realización del procedimiento.

Mi solución para que era bastante simple en realidad; el establecimiento de un método atributo y prueba de su presencia después. He aquí una simplificación de todo el asunto:

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

ACTUALIZACIÓN:. En realidad llamar method() de run_method() (? No es que el espíritu) y tienen que pasar todos los argumentos sin modificar el método

P.S .: Esta respuesta no responde directamente a la pregunta. En mi humilde opinión, hay dos razones que uno quiere saber qué clase define un método; primero es señalar con el dedo a una clase en código de depuración (tales como en el manejo de excepciones), y el segundo es para determinar si ha sido re-implementado el método (donde el método es a trozo destinado a ser ejecutado por el programador). Esta respuesta resuelve el segundo caso de una manera diferente.

En Python 3, si usted necesita la clase de objeto real que puede hacer:

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

Si la función podría pertenecer a una clase anidada que se necesita para recorrer la siguiente manera:

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top