메서드를 정의한 클래스 가져 오기
파이썬에서 메서드를 정의한 클래스를 어떻게 얻을 수 있습니까?
다음 예제에서 " __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)
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
내가 요점을 놓치고 있다는 것을 지적 해 주신 Sr2222에게 감사드립니다 ...
다음은 Alex와 비슷하지만 아무것도 가져올 필요가없는 수정 된 접근 방식입니다. 이 접근 방식은 전체 상속을 반환하는 대신 정의 클래스가 발견 되 자마자 중지되므로 상속 된 클래스의 거대한 계층 구조가없는 한 개선이라고 생각 getmro하지 않습니다. 말했듯이 이것은 매우 드문 시나리오입니다.
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
그리고 예 :
>>> 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
Alex 솔루션은 동일한 결과를 반환합니다. Alex 접근 방식을 사용할 수있는 한이 방법 대신 사용합니다.
I don't know why no one has ever brought this up or why the top answer has 50 upvotes when it is slow as hell, but you can also do the following:
def get_class_that_defined_method(meth):
return meth.im_class.__name__
For python 3 I believe this changed and you'll need to look into .__qualname__.
I started doing something somewhat similar, basically the idea was checking whenever a method in a base class had been implemented or not in a sub class. Turned out the way I originally did it I could not detect when an intermediate class was actually implementing the method.
My workaround for it was quite simple actually; setting a method attribute and testing its presence later. Here's an simplification of the whole thing:
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: Actually call method() from run_method() (isn't that the spirit?) and have it pass all arguments unmodified to the method.
P.S.: This answer does not directly answer the question. IMHO there are two reasons one would want to know which class defined a method; first is to point fingers at a class in debug code (such as in exception handling), and the second is to determine if the method has been re-implemented (where method is a stub meant to be implemented by the programmer). This answer solves that second case in a different way.
In Python 3, if you need the actual class object you can do:
import sys
f = Foo.my_function
vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]] # Gets Foo object
If the function could belong to a nested class you would need to iterate as follows:
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
참고URL : https://stackoverflow.com/questions/961048/get-class-that-defined-method
'Programing' 카테고리의 다른 글
| Python 3-인코딩 / 디코딩 대 바이트 / Str (0) | 2020.10.25 |
|---|---|
| 서로 의존하는 속성을 초기화하는 방법 (0) | 2020.10.25 |
| "메모리 오류로 인해 종료 됨"을 디버깅 할 수 있습니까? (0) | 2020.10.25 |
| 요점의 마크 다운 파일에서 이미지에 대한 상대 링크를 만들 수 있습니까? (0) | 2020.10.24 |
| AngularJs 복잡한 데이터를 지시문에 전달 (0) | 2020.10.24 |