문제

파이썬에서 메소드를 정의한 클래스를 어떻게 얻을 수 있습니까?

나는 다음 예제를 인쇄하고 싶다 "__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 하다. 말했듯이, 이것은 a입니다 매우 아마도 시나리오.

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 Solution은 동일한 결과를 반환합니다. Alex 접근법을 사용할 수있는 한, 나는 이것 대신에 그것을 사용할 것입니다.

나는 왜 아무도 이것을 제기 한 적이 없는지 또는 왜 대답이 지옥처럼 느리면 50 개의 upvotes를 가지고있는 이유를 모르겠지만, 당신은 다음을 수행 할 수 있습니다.

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

Python 3의 경우 나는 이것이 바뀌 었다고 생각하며 당신은 조사해야합니다. .__qualname__.

나는 기본적으로 기본 클래스의 메소드가 구현되었거나 하위 클래스에서 구현 될 때마다 아이디어가 확인하는 것이 다소 비슷한 일을 시작했습니다. 내가 원래했던 방식이 밝혀졌습니다. 중간 클래스가 실제로 메소드를 구현했을 때를 감지 할 수 없었습니다.

내 해결 방법은 실제로 매우 간단했습니다. 메소드 설정 기인하다 나중에 그 존재를 테스트합니다. 다음은 모든 것의 단순화입니다.

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

업데이트 : 실제로 전화하십시오 method() ~에서 run_method() (그 정신이 아니십니까?) 그리고 모든 논증을 방법에 수정하지 않은 모든 논증을 통과하게하십시오.

추신 :이 답변은 질문에 직접 대답하지 않습니다. IMHO 어떤 클래스가 메소드를 정의했는지 알고 싶어하는 두 가지 이유가 있습니다. 첫 번째는 디버그 코드의 클래스 (예 : 예외 처리)에서 손가락을 가리키는 것이며, 두 번째는 메소드가 다시 구현되었는지 여부를 결정하는 것입니다 (여기서 메소드가 프로그래머가 구현 해야하는 스터브입니다). 이 답변은 두 번째 사례를 다른 방식으로 해결합니다.

Python 3에서는 실제 클래스 객체가 필요한 경우 다음을 수행 할 수 있습니다.

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

함수가 중첩 클래스에 속할 수있는 경우 다음과 같이 반복해야합니다.

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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top