Jak mogę uzyskać klasę, która zdefiniowała metodę w Pythonie?
Chciałbym, aby następujący przykład wyświetlał „ __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
źródło
źródło
Odpowiedzi:
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
źródło
__dict__
! Czasami__slots__
jest używany. Prawdopodobnie lepiej jest użyćgetattr
do sprawdzenia, czy metoda znajduje się w klasie.Python 3
, proszę odnieść się do tej odpowiedzi .'function' object has no attribute 'im_class'
Dzięki Sr2222 za wskazanie, że nie rozumiem ...
Oto poprawione podejście, które jest podobne do podejścia Alexa, ale nie wymaga niczego importowania. Nie sądzę jednak, że jest to poprawa, chyba że istnieje ogromna hierarchia klas dziedziczonych, ponieważ to podejście zatrzymuje się, gdy tylko zostanie znaleziona klasa definiująca, zamiast zwracać całe dziedziczenie
getmro
. Jak powiedziałem, jest to bardzo mało prawdopodobny scenariusz.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
I przykład:
>>> 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
Rozwiązanie Alex zwraca te same wyniki. O ile można zastosować podejście Alexa, użyłbym go zamiast tego.
źródło
Cls().meth.__self__
po prostu podaje przykład,Cls
który jest powiązany z tym konkretnym wystąpieniemmeth
. To jest analogiczne doCls().meth.im_class
. Jeśli takclass SCls(Cls)
,SCls().meth.__self__
otrzymaszSCls
instancję, a nieCls
instancję. To, czego chce OP, to dostaćCls
, co wydaje się dostępne tylko chodząc po MRO, tak jak robi to @Alex Martelli.Nie wiem, dlaczego nikt nigdy o tym nie wspominał ani dlaczego najlepsza odpowiedź ma 50 głosów pozytywnych, kiedy jest wolna jak diabli, ale możesz też wykonać następujące czynności:
def get_class_that_defined_method(meth): return meth.im_class.__name__
Uważam, że w przypadku Pythona 3 to się zmieniło i musisz się temu przyjrzeć
.__qualname__
.źródło
W Pythonie 3, jeśli potrzebujesz rzeczywistego obiektu klasy, możesz zrobić:
import sys f = Foo.my_function vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]] # Gets Foo object
Jeśli funkcja mogłaby należeć do zagnieżdżonej klasy, należałoby wykonać iterację w następujący sposób:
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
źródło
Zacząłem robić coś podobnego, zasadniczo chodziło o sprawdzenie, czy metoda w klasie bazowej została zaimplementowana, czy nie w podklasie. Okazało się, że tak jak pierwotnie to zrobiłem, nie mogłem wykryć, kiedy klasa pośrednia faktycznie implementowała tę metodę.
Moje obejście było całkiem proste; ustawienie atrybutu metody i późniejsze sprawdzenie jego obecności. Oto uproszczenie całej rzeczy:
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
AKTUALIZACJA: Właściwie wywołaj
method()
fromrun_method()
(czy to nie jest duch?) I przekaż wszystkie niezmodyfikowane argumenty do metody.PS: Ta odpowiedź nie odpowiada bezpośrednio na pytanie. IMHO Istnieją dwa powody, dla których chciałoby się wiedzieć, która klasa zdefiniowała metodę; pierwszym jest wskazanie palcem klasy w kodzie debugowania (na przykład w obsłudze wyjątków), a drugim jest określenie, czy metoda została ponownie zaimplementowana (gdzie metoda jest kodem pośrednim przeznaczonym do zaimplementowania przez programistę). Ta odpowiedź rozwiązuje ten drugi przypadek w inny sposób.
źródło
Python 3
Rozwiązałem to w bardzo prosty sposób:
str(bar.foo_method).split(" ", 3)[-2]
To daje
'FooClass.foo_method'
Podziel na kropkę, aby osobno pobrać klasę i nazwę funkcji
źródło