¿Cómo puedo obtener la clase que definió un método en Python?
Me gustaría que el siguiente ejemplo imprima " __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
fuente
fuente
Respuestas:
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
fuente
__dict__
! A veces__slots__
se usa. Probablemente sea mejor usarlogetattr
para probar si el método está en la clase.Python 3
, consulte esta respuesta .'function' object has no attribute 'im_class'
Gracias Sr2222 por señalar que me estaba perdiendo el punto ...
Aquí está el enfoque corregido que es como el de Alex pero no requiere importar nada. Sin embargo, no creo que sea una mejora, a menos que haya una gran jerarquía de clases heredadas, ya que este enfoque se detiene tan pronto como se encuentra la clase definitoria, en lugar de devolver toda la herencia como lo
getmro
hace. Como se dijo, este es un escenario muy 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
La solución de Alex devuelve los mismos resultados. Siempre que se pueda usar el enfoque de Alex, lo usaría en lugar de este.
fuente
Cls().meth.__self__
solo le da la instancia deCls
que está vinculada a esa instancia específica demeth
. Es análogo aCls().meth.im_class
. Si es asíclass SCls(Cls)
,SCls().meth.__self__
obtendrá unaSCls
instancia, no unaCls
instancia. Lo que quiere el OP es obtenerCls
, que parece que solo está disponible caminando por el MRO como lo hace @Alex Martelli.No sé por qué nadie ha mencionado esto o por qué la respuesta principal tiene 50 votos a favor cuando es lento como el infierno, pero también puede hacer lo siguiente:
def get_class_that_defined_method(meth): return meth.im_class.__name__
Para Python 3, creo que esto cambió y tendrás que investigar
.__qualname__
.fuente
En Python 3, si necesita el objeto de clase real, puede hacer:
import sys f = Foo.my_function vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]] # Gets Foo object
Si la función pudiera pertenecer a una clase anidada, necesitaría iterar de 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
fuente
Empecé a hacer algo similar, básicamente la idea era comprobar cada vez que un método en una clase base se había implementado o no en una subclase. Resultó que, de la forma en que lo hice originalmente, no pude detectar cuándo una clase intermedia estaba implementando el método.
En realidad, mi solución fue bastante simple; establecer un atributo de método y probar su presencia más tarde. Aquí hay una simplificación de todo:
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: Realmente llame
method()
desderun_method()
(¿no es ese el espíritu?) Y haga que pase todos los argumentos sin modificar al método.PD: Esta respuesta no responde directamente a la pregunta. En mi humilde opinión, hay dos razones por las que uno querría saber qué clase define un método; el primero es señalar con el dedo a una clase en el código de depuración (como en el manejo de excepciones), y el segundo es determinar si el método se ha vuelto a implementar (donde el método es un código auxiliar destinado a ser implementado por el programador). Esta respuesta resuelve ese segundo caso de una manera diferente.
fuente
Python 3
Lo solucionó de una manera muy sencilla:
str(bar.foo_method).split(" ", 3)[-2]
Esto da
'FooClass.foo_method'
Dividir en el punto para obtener la clase y el nombre de la función por separado
fuente