Como posso obter a classe que definiu um método em Python?
Eu gostaria que o seguinte exemplo imprimisse " __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
fonte
fonte
Respostas:
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
fonte
__dict__
! Às vezes__slots__
é usado. Provavelmente é melhor usargetattr
para testar se o método está na classe.Python 3
, consulte esta resposta .'function' object has no attribute 'im_class'
Obrigado Sr2222 por apontar que eu estava perdendo o ponto ...
Aqui está a abordagem corrigida, que é igual à de Alex, mas não exige a importação de nada. No entanto, não acho que seja uma melhoria, a menos que haja uma enorme hierarquia de classes herdadas, já que essa abordagem para assim que a classe definidora é encontrada, em vez de retornar toda a herança como o
getmro
faz. Como disse, este é um cenário muito improvável.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 o exemplo:
>>> 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
A solução de Alex retorna os mesmos resultados. Contanto que a abordagem de Alex possa ser usada, eu a usaria em vez desta.
fonte
Cls().meth.__self__
apenas fornece a instância deCls
que está ligada a essa instância específica demeth
. É análogo aCls().meth.im_class
. Em caso afirmativoclass SCls(Cls)
,SCls().meth.__self__
obterá umaSCls
instância, não umaCls
instância. O que o OP quer é obterCls
, o que parece estar disponível apenas caminhando pelo MRO como @Alex Martelli faz.Não sei por que ninguém mencionou isso ou por que a resposta principal tem 50 votos positivos quando é lenta como o diabo, mas você também pode fazer o seguinte:
def get_class_that_defined_method(meth): return meth.im_class.__name__
Para python 3, acredito que isso mudou e você precisará dar uma olhada
.__qualname__
.fonte
No Python 3, se você precisa do objeto de classe real, pode fazer:
import sys f = Foo.my_function vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]] # Gets Foo object
Se a função pudesse pertencer a uma classe aninhada, você precisaria iterar da seguinte maneira:
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
fonte
Python 3
Resolvido de uma forma muito simples:
str(bar.foo_method).split(" ", 3)[-2]
Isto dá
'FooClass.foo_method'
Divida no ponto para obter a classe e o nome da função separadamente
fonte
Comecei fazendo algo um tanto semelhante, basicamente a ideia era verificar se um método em uma classe base havia sido implementado ou não em uma subclasse. Da maneira como fiz originalmente, não consegui detectar quando uma classe intermediária estava realmente implementando o método.
Minha solução alternativa foi bastante simples; definir um atributo de método e testar sua presença posteriormente. Aqui está uma simplificação de tudo:
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
ATUALIZAÇÃO: Realmente chame
method()
derun_method()
(não é esse o espírito?) E passe todos os argumentos não modificados para o método.PS: Esta resposta não responde diretamente à pergunta. IMHO, existem duas razões pelas quais alguém gostaria de saber qual classe definiu um método; o primeiro é apontar o dedo para uma classe no código de depuração (como no tratamento de exceções) e o segundo é determinar se o método foi reimplementado (onde método é um esboço para ser implementado pelo programador). Essa resposta resolve o segundo caso de uma maneira diferente.
fonte