2012-11-30 4 views
1

실행시 기존 클래스에 새 클래스를 추가하려고합니다 ("type (...)"사용). 나는 또한 새로운 클래스 '__getattr__을 재정의하여 새로운 클래스에 속하지 않은 속성에 대한 고유 한 동작을 수행 할 수 있도록하려고합니다. 예를 들어 클래스 foo가 있고, 클래스 "tool"을 추가하고 foo.tool.test 이 내 자신의 일을하고 싶습니다. 아래의 코드는 부분적으로 만 작동합니다. 명시 적으로 __getattr__을 호출하면 작동합니다 (첫 번째 인쇄 참조). 하지만 foo.tool.test를 참조하면 재정의 된 __getattr__이 호출되지 않고 attrbute 오류가 발생합니다.python - 동적으로 추가 된 클래스에 대해 __getattr__을 재정의하려하지만 일종의 작업 만

귀하의 도움에 감사드립니다.

class Foo(object): 
    def __init__(self): 
     self.NameList=[] 
     # add new class to ourself 
     self.tool = type('tool', (object,), {}) 
     # override new class' __getattr__ with call to ourself 
     setattr(self.tool, "__getattr__", self.__getattr__) 
     # add one well known test name for now 
     self.NameList.append("test") 

    # should be called by our newly added "tool" object but is only called sometimes... 
    def __getattr__(self, attr): 
     # print("__getattr__: %s" % attr) 
     if(attr in self.NameList):  
      return(99) 
     raise AttributeError("--%r object has no attribute %r" % (type(self).__name__, attr))  

foo = Foo() 
# access tool class attribute "test" - it should be seen by the override __getattr__ 
# the following works... 
print("foo.tool.__getattr__=%d" % foo.tool.__getattr__("test")) 
# but the following does not - why is this not the same as the line above??? 
print("foo.tool.test=%d" % foo.tool.test)       
+0

뿐만 아니라'object'으로 사용합니다. '__getattr__'는'tool'의 인스턴스에서 정상적으로 작동합니다. 예.'foo.tool(). test' –

답변

6

파이썬은 인스턴스의 기지가 아닌 인스턴스의 __dict__에서 __dict__의에서 __getattr__ 같은 특별한 방법을 찾습니다.

self.tool은 클래스입니다. 따라서 self.tool.test__getattr__self.tool의 클래스 (즉, object)라고합니다. 이는 우리가 원하는 것이 아닙니다.

class Foo(object): 
    def __init__(self): 
     self.NameList=[] 
     # add new class to ourself 
     toolcls = type('tool', (object,), { '__getattr__' : self.__getattr__, }) 
     self.tool = toolcls() 
     self.NameList.append("test") 

    # should be called by our newly added "tool" object but is only called sometimes... 
    def __getattr__(self, attr): 
     # print("__getattr__: (%s, %s)" % (self.__class__.__name__, attr)) 
     if(attr in self.NameList):  
      return(99) 
     raise AttributeError("--%r object has no attribute %r" % (
      type(self).__name__, attr)) 

foo = Foo() 
print("foo.tool.__getattr__=%d" % foo.tool.__getattr__("test")) 
print("foo.tool.test=%d" % foo.tool.test)  

는 또한

foo.tool.__getattr__=99 
foo.tool.test=99 

산출, Foo의 인스턴스 인 경우에는, 상기 코드는 무한 순환을 초래할 수 있음에주의 :

대신에 그 클래스를 갖는 __getattr__, self.tool에 인스턴스를 만들기 self.NameList이 정의되지 않았습니다. Ned Batchelder's post on this suprising pitfall을 참조하십시오.

, 여기에 무한 재귀의 가능성을 방지

def __getattr__(self, attr): 
    # print("__getattr__: (%s, %s)" % (self.__class__.__name__, attr)) 
    if attr == 'NameList': 
     raise AttributeError() 
    if(attr in self.NameList):  
     return(99) 
    raise AttributeError("--%r object has no attribute %r" % (
     type(self).__name__, attr)) 
당신은 클래스로 tool``를 참조
+0

설명에 감사드립니다. 나는 그것을 몇 번 더 읽어야한다. 나는 Foo 밖에서 클래스를 정의함으로써 작동하도록 만들었지 만 최종 결과는 너와 동일하다 - 너는 훨씬 더 간결하고 컴팩트하고 독립적이다. – staggart

+0

Opps가 너무 일찍 반환됩니다. py가 base의 __dict __ [__ getattr__]을 사용하고 인스턴스의 값을 사용하지 않는 이유는 무엇입니까? 그리고 관련하여, 왜 내가 "setattr (self.tool ...)을 수행했는지와 다른 __getattr__을 추가하는 toolcls의 인스턴스화가 무엇입니까? – staggart

+0

@staggart : 설명하는 문서에 대한 링크를 찾을 수 있으면 좋겠지 만 불행히도 나는 그것을 찾을 수 없었습니다. 고전적인 클래스가 아닌'new-style' 클래스에 대해서 인스턴스가 아닌 특별한 메소드가 클래스에서 검색되었습니다. 고전 클래스에서는'__add__' 메소드를 사용할 수 있습니다 인스턴스의'__dict__'에서'x + y'에 대한 특수한 동작을 얻지 만 새로운 스타일의 클래스에서는 그렇지 않습니다. 이제 클래스의'__dict__'에'__add__'을 넣어야합니다 .. – unutbu