2012-08-13 1 views
2

제 질문은 this one과 다소 비슷합니다. 그것은 모듈 내용보다는 객체 방법에 관한 것이다. inspect 모듈을 사용하여 클래스가 정의 된 메서드를 가져올 수 있는지 알고 싶습니다. 부모 클래스가 아니라에 대한 질문입니다.Python - 메서드가 정의 된 클래스를 쿼리하려면 어떻게해야합니까?

내 자식 클래스가 더 높은 수준의 추상화 수준에서 부모 메서드에 액세스하는 '매크로'메서드를 정의하고 모든 하위 수준 메서드에 대해 걱정할 필요가 없기 때문에이 메서드가 필요합니다. 상속 나무를 올리십시오. 여기

은 간단한 예입니다 :

class Foo(object): 
    def __init__(self): pass 
    def f1(self): return 3 
    def f2(self): return 1 

class Bar(Foo): 
    def __init__(self): Foo.__init__(self) 
    def g1(self): return self.f1() + self.f2() 
    def g2(self): return self.f1() - self.f2() 

import inspect 
inspect.getmembers(Bar, inspect.ismethod) 

출력 :

[('__init__', <unbound method Bar.__init__>), 
('f1', <unbound method Bar.f1>), 
('f2', <unbound method Bar.f2>), 
('g1', <unbound method Bar.g1>), 
('g2', <unbound method Bar.g2>)] 
그녀는 이제까지에 관심이있을 것 때문에

사용자가 알거나 f의의 존재에 대해 관심이 필요 g s. (물론 이러한 결과는 대부분의 컨텍스트에서 의미가 있습니다. 인스턴스화 될 때 이러한 모든 메서드가 개체에 바인딩되기 때문입니다.) 긴 상속 트리의 경우 반환 된 목록은 매우 길어지고 사용자와 관련이 없습니다.

f1f2을 어떻게 제거 할 수 있습니까? 클래스에 정의 된 메소드에 대해 __module__ 속성에 해당하는 것이 있습니까? 더 나은 방법은 인스턴스 메서드를 사용하여 동일한 작업을 수행 할 수 있습니까?

+0

바운드 메소드 ('Bar'의 인스턴스)에서'im_class'를 요구하는 것이 작동하지 않습니다. 또한 바인딩되지 않은 메서드에서도 작동하지 않습니다. –

+1

'object.hasOwnPro ...'안돼, 그게 옳지 않아. (죄송 합니다만, JavaScript가 Python보다 더 쉽게 할 수 있다는 것을 믿을 수 없었습니다.) – kojiro

답변

5

방법, im_class 속성이 문제의 클래스를 가리키는. 당신은 클래스의 구성원 인 기능에 해당 필터를 사용할 수있는 것은 :

inspect.getmembers(Bar, 
    lambda m: inspect.ismethod(m) and m.__func__ in m.im_class.__dict__.values()) 

이 당신에게 제공합니다

물론
[ 
    ('__init__', <unbound method Bar.__init__>), 
    ('f1', <unbound method Bar.f1>), 
    ('f2', <unbound method Bar.f2>) 
] 

, 당신은 단지 모두 다음 getmembers을 우회 할 수있다 :

[m for m in Bar.__dict__.values() if inspect.isfunction(m)] 

제공 :

[<function __init__ at 0x100a28de8>, <function g1 at 0x100a28e60>, <function g2 at 0x100a28ed8>] 
이것은 바운드 또는 언 바운드 방법에 적용

, 그들은 같은 .__func__ (또는 im_func, 이전 이름) 속성을 가지고있다. bound와 unbound의 차이는 .__self__ 속성의 값입니다 (언 바운드 할 경우 없음).

이러한 "비밀"속성은 모두 Python Data Model에 문서화되어 있습니다.

+0

와우 ... 이것은 마치 흑 마법처럼 보입니다. 이 물건을 어디서 배웠 니? (+1) – mgilson

+0

@mgilson : 포인터 추가; 또한'dir()'은 언제나처럼 당신의 친구입니다. 필자는 필자의 커리어에서 가장 위대한 파이썬 개발자 중 한 명과 함께 일하면서 장점을 얻었습니다. :-) –

+0

Ahh ... 저는 파이썬의 내부 동작을 깊게 파고들 필요가 없었으며 놀라운 내성 능력을 가지고있었습니다 (내 순진한 대답으로는 분명합니다). 나는 마치 전체 데이터 모델을 암기 한 것처럼 흥미로운 질문에 대답 할 수있는 능력에 자주 놀라곤합니다. – mgilson

2

희망 누군가가 더 나은 솔루션과 함께 제공하지만, 무엇에 대한 것입니다 : 물론

foo_members = inspect.getmembers(Foo,inspect.ismethod) 
bar_members = inspect.getmembers(Bar,inspect.ismethod) 

set(bar_members) - set(foo_members) 

실제 상황에서, 당신은 실제로 모든 것을 제거 당신이하지 얻을 Bar.__bases__을 통해 걸어해야 할 수도 있습니다 필요.

예컨대 :

set(bar_members) - set(sum([inspect.getmembers(base,inspect.ismethod) for base in Bar.__bases__],[])) 
+0

또는 좀 더 일반적인 해결책을 위해 하드 코딩 된 Foo 대신 Bar .__ bases__를 사용하십시오. – Alfe

+0

@Alfe -'__mro__'을'__bases__ '로 변경하고 예제를 추가했습니다. – mgilson