2012-02-06 4 views
4

저는 사용자 정의 속성 액세스를 제공하기 위해 __setattr____getattr__을 사용하는 파이썬 클래스를 작성하고 있습니다.파이썬 클래스에 __setattr__과 설명자를 모두 사용합니다.

그러나 일부 속성은 일반적인 방법으로 처리 할 수 ​​없으므로 해당 속성에 대해 설명자를 사용하고 싶습니다.

문제는, 기술자의 __get__이 인스턴스 __getattr__ 찬성 호출됩니다 기술자에 대한한다는 점에서 발생하지만, 속성에 할당 할 때, __setattr__는 설명 __set__ 찬성 호출됩니다.

예 :

class MyDesc(object): 

    def __init__(self): 
     self.val = None 

    def __get__(self, instance, owner): 
     print "MyDesc.__get__" 
     return self.val 

    def __set__(self, instance, value): 
     print "MyDesc.__set__" 
     self.val = value 

class MyObj(object): 

    foo = MyDesc() 

    def __init__(self, bar): 
     object.__setattr__(self, 'names', dict(
      bar=bar, 
     )) 
     object.__setattr__(self, 'new_names', dict()) 

    def __setattr__(self, name, value): 
     print "MyObj.__setattr__ for %s" % name 
     self.new_names[name] = value 

    def __getattr__(self, name): 
     print "MyObj.__getattr__ for %s" % name 

     if name in self.new_names: 
      return self.new_names[name] 

     if name in self.names: 
      return self.names[name] 

     raise AttributeError(name) 

if __name__ == "__main__": 
    o = MyObj('bar-init') 

    o.bar = 'baz' 
    print o.bar 

    o.foo = 'quux' 
    print o.foo 

인쇄 : 기술자의이 __set__가 호출되지 않습니다

MyObj.__setattr__ for bar 
MyObj.__getattr__ for bar 
baz 
MyObj.__setattr__ for foo 
MyDesc.__get__ 
None 

. __setattr__ 정의는 단지 이름의 제한된 집합에 대한 동작을 오버라이드 (override)되지 않기 때문에

는 경우, 속성에 기술자를 사용하여 할당해야하는 권장 방법이 있나요이 object.__setattr__

로 연기 할 수 명확한 곳이 없습니다 사용할 수 있으며 __setattr__? 가능한 방법의

답변

3

은 내가 자동으로 각 클래스에서 기술자가있는 표시하고 그 이름을 객체의 정상적인 동작을 호출 할 거라고 방식으로 __setattr__을 포장하는 메커니즘을함으로써이 문제를 접근 거라고 생각합니다.

이 쉽게 당신이 방법은 작동하지 않습니다 둘째있어 메타 클래스 (및 __setattr__

def setattr_deco(setattr_func): 
    def setattr_wrapper(self, attr, value): 
     if attr in self._descriptors: 
      return object.__setattr__(self, attr, value) 
     return setattr_func(self, attr, value) 
    return setattr_wrapper 

class MiscSetattr(type): 
    def __new__(metacls, name, bases, dct): 
     descriptors = set() 
     for key, obj in dct.items(): 
      if key == "__setattr__": 
       dct[key] = setattr_deco(obj) 
      elif hasattr(obj, "__get__"): 
       descriptors.add(key) 
     dct["_descriptors"] = descriptors 
     return type.__new__(metacls, name, bases, dct) 

# and use MiscSetattr as metaclass for your classes 
4

하나는 : 이름이 이미 클래스, 기본 클래스 또는 인스턴스에 정의 된 경우

def __setattr__(self, name, value): 
    print "MyObj.__setattr__ for %s" % name 
    for cls in self.__class__.__mro__ + (self,): 
     if name in cls.__dict__: 
      return object.__setattr__(self, name, value) 
    print 'New name', name, value 
    self.new_names[name] = value 

이 확인하고 다음은 설명 __set__를 실행합니다 object.__setattr__ 호출합니다.

또 다른 방법 :

def __setattr__(self, name, value): 
    print "MyObj.__setattr__ for %s" % name 
    try: 
     object.__getattribute__(self, name) 
    except AttributeError: 
     print 'New name', name, value 
     self.new_names[name] = value 
    else: 
     object.__setattr__(self, name, value) 

하지만 기술자의 __get__를 호출합니다.

P.

MyObj에는 __dict__에 상속 된 클래스 멤버가 포함되므로 모두 __mro__ 멤버를 확인해야할지 확실하지 않습니다.

for cls in (self.__class__, self):...이면 충분합니다.

+0

위한 장식으로 달성 될 수있다. 내 예를 들어, 당신은 개체에 새 속성을 설정할 수있어 그 이미 존재하지 않았고,이 방법은 그것을 허용하지 않을 것입니다. – SpoonMeiser

+0

@SpoonMeiser, 나는 당신의 것과 비슷하다고 생각합니다 .http : //ideone.com/HMBcc보세요. 아마도 내가 놓친 것 같아요. – reclosedev

+0

만약 제가' 'quux'] '대신'o.__ dict __ ['quux ']'가 설정됩니다. – SpoonMeiser

관련 문제