2010-02-18 7 views
3

조건에 따라 클래스 인스턴스의 모든 메서드를 빠르게 비활성화하려면 어떻게합니까? 내 순진한 해결책은 __getattr__을 사용하여 재정의하는 것이지만 함수 이름이 이미 존재하면 호출되지 않습니다.클래스 인스턴스 메서드 사용 안 함

class my(): 
    def method1(self): 
     print 'method1' 
    def method2(self): 
     print 'method2' 
    def __getattr__(self, name): 
     print 'Fetching '+str(name) 
     if self.isValid(): 
      return getattr(self, name) 
    def isValid(self): 
     return False 
if __name__ == '__main__': 
    m=my() 
    m.method1() 
+0

왜? 이 용도는 무엇입니까? 액세스를 "비활성화"해야하는 상황을 제공 할 수 있습니까? 어떤 액세스 권한을 사용 중지 하시겠습니까? 그냥 메서드 함수? 'if' 문을 쓰지 않는 이유는 무엇입니까? ** 주 ** 디자인 패턴의 예입니까? –

+1

이 질문은 단일 지점/사후 솔루션에 대한 검색을 의미하며,이 경우 __getaddr__ 접근 방식이 유일한 방법 인 것처럼 보입니다. Alex의 대답에 강조되어있는 바와 같이, 모든 단일 속성 액세스는 오버 헤드를 겪게 될 것입니다. isValid 상태를 테스트하고 직접 반환하거나 원래 메서드로 전달하는 데코레이터를 고려 했습니까? 이 접근법은 모든 (대부분의) 메소드에 "변경"을 요구하지만, 프로세스에 대한 더 많은 제어를 제공하고 모든 단일 속성이 아닌 메소드에만 영향을 미칩니다. 어떤면에서 S Lott의 제안에 더 가까워지고 있습니다. – mjv

+0

mjv에서 말한 것처럼 클래스가 특정 상태에있을 때 사용자가 메서드에 액세스하지 못하도록 일반화 된 메커니즘이 필요했습니다. 즉, 고객의 클래스가 아직 고객의 이름을 읽지 않았을 때 값 오류가 발생했습니다. db. 나는 각각의 방법으로 그것을 키우고 싶지 않았다. 초심자 파이썬 프로그래머로서, 나는 이러한 모든 수표를 중앙 집중식 장소에서 처리하는 더 좋은 방법이있을 것이라고 생각했습니다. –

답변

5

당신이 원하는 무엇의 상당 실제로 모든 액세스 속성을 촉구 할 예정이다 __getattribute__을 무시하는 것입니다. 매우 느리다는 것 외에도, 의 정의에 따라 각각, 예를 들어. __getattribute__ 내의 self.isValid에 대한 호출이므로 해당 속성에 액세스하기 위해 순환 경로를 사용해야합니다 (예 : type(self).isValid(self)은 인스턴스가 아닌 클래스에서 속성을 가져옴).

이 끔찍한 용어의 혼란을 가리키는이 "는 클래스의 방법"을 사용하지 하지입니다하지만 예를에서, 특히 classmethods과는 아무 상관이 없습니다. 인스턴스 기반이 아닌 클래스 기반으로 유사한 방식으로 작업하려는 경우 사용자 지정 메타 클래스를 만들어서에 __getattribute__(이 속성은 에 액세스 할 때 호출 된 것임)을 재정의해야합니다. 계좌 번호 - 귀하의 제목과 텍스트에서 묻는대로 (예 :) - 사실 당신이하고있는 것처럼 보입니다. 이는 훨씬 더 평범하고 일반적인 경우입니다.

편집 : 전혀 다른 접근 방식은 State 디자인 패턴을 구현하는 데 특별한 Pythonic 경로를 사용하는 것일 수 있습니다 : class-switching. 예 :만큼 객체의 __class__ 적절하게 전환 있도록 적절하게 setValid를 호출 할 수

class _NotValid(object): 
    def isValid(self): 
    return False 
    def setValid(self, yesno): 
    if yesno: 
     self.__class__ = TheGoodOne 

class TheGoodOne(object): 
    def isValid(self): 
    return True 
    def setValid(self, yesno): 
    if not yesno: 
     self.__class__ = _NotValid 
    # write all other methods here 

이 매우 빠르고 간단합니다 - 모든 객체의 메소드가 발견되는 경우 기본적으로 개체의 __class__는, 그래서 이를 전환하면 주어진 시간에 객체에 존재하는 메소드 세트를 전환 할 수 있습니다. 그러나 유효성 검사가 "적절한 시간에"수행되어야한다고 절대적으로 주장하는 경우 즉, 개체의 메서드를 조회하는 바로 그 순간에이 방법은 효과가 없습니다.

이것과 중간의 접근법 __getattribute__ 하나의 라인을 따라, 일반적으로 모든 문제의 해결책 ;-)로 유지되어 간접적 인 여분의 레벨을 (소개 될 것이다 :

class _Valid(object): 
    def __init__(self, actualobject): 
    self._actualobject = actualobject 
    # all actual methods go here 
    # keeping state in self._actualobject 

class Wrapit(object): 
    def __init__(self): 
    self._themethods = _Valid(self) 
    def isValid(self): 
    # whatever logic you want 
    # (DON'T call other self. methods!-) 
    return False 
    def __getattr__(self, n): 
    if self.isValid(): 
     return getattr(self._themethods, n) 
    raise AttributeError(n) 

이것은 __getattr__이 다른 방법으로는 찾을 수없는 속성에 대해서만 호출되므로 객체가 __dict__에 정상 상태 (데이터)를 유지할 수 있고 어떤 객체도없이 액세스 할 수 있기 때문에 __getattribute__보다 관용적입니다. 큰 오버 헤드; only 메소드 호출은 indiretion의 추가 오버 헤드를 지불합니다. _Valid 클래스 인스턴스는 유효하지 않은 객체에 액세스 할 수 있어야하는 상태가 있으면 해당 self._actualobject에 일부 또는 전체 상태를 유지할 수 있습니다 (유효하지 않은 상태 사용 방법이 아닌 데이터 속성 액세스). 필요하지만이 방법으로 제공되는 무료 추가 가능성이 있습니다). 이 관용법은 __getattribute__보다 에러가 발생하기 쉽지만, 상태가 메소드에서 더 직접적으로 액세스 될 수 있기 때문에 (유효성 검사를 트리거하지 않고).

제시된 것처럼 솔루션은 가비지 수집과 관련하여 약간의 오버 헤드를 부과 할 수있는 순환 참조 루프를 만듭니다. 응용 프로그램에 문제가있는 경우 표준 Python 라이브러리의 weakref 모듈을 사용하십시오.이 모듈은 일반적으로 참조 순환 루프를 제거하는 가장 간단한 방법입니다. 문제가있는 경우 해당 모듈을 순환 삭제하십시오. 예 : _actualobject 속성이 _Valid 클래스 인스턴스 인 이 약 인 것으로 해당 인스턴스가 해당 _themethods 속성으로 유지되는 것을 참조하십시오.

+0

포인트가 찍히고, 내가 관심이있는 인스턴스입니다! –

+0

인스턴스에서 __getattribute__를 트리거하지 않고 self.isValid()를 찾는 것은 매우 까다 롭습니다! –

+1

위의 답변에서 제안하는 특정 표현식의 잘못된 점은'type (self) .isValid (self)'입니까? 물론'isValid' 메쏘드 자체는'self'의 속성에 접근하지 않고 (예를 들어'self .__ dict__'를 보면서) 스스로 처리해야합니다. 이 일반적인 접근법을 주장한다면 잠재적 인 함정으로 가득차 있지만 가능합니다. 그렇지 않으면 접근하기 쉬운 방법을 선택할 수 있습니다. 귀하의 Q 또는 다른 사람들에게 의견에 제안 된 것들 (아직 내 A를 편집하도록 권유하십시오). –