2013-08-27 1 views
2

토글 가능한 버전의 사전 도트 액세스를 아직 보지 못했습니다. 여기Python dicts에 전환식 도트 액세스가 가능합니까?

내 첫 패스 시도가 작동하지 않습니다

class DottableDict (dict): 

    def allowDotting (self, state=True): 
     if state: 
      self.__setattr__ = dict.__setitem__ 
      self.__getattr__ = dict.__getitem__ 
     else: 
      del self.__setattr__ 
      del self.__getattr__ 

>>> import dot 
>>> d = dot.DottableDict() 
>>> d.allowDotting() 
>>> d.foo = 'bar' 
>>> d 
{} 
>>> d.foo 
'bar' 
>>> d.__dict__ 
{'__setattr__': <slot wrapper '__setitem__' of 'dict' objects>, 'foo': 'bar', 
'__getattr__': <method '__getitem__' of 'dict' objects>} 
>>> d.allowDotting(False) 
>>> d.__dict__ 
{'foo': 'bar'} 

나는 서명 않은 setattr 및 setitem 사이에 일치하지 않는 생각합니다.

내 두 번째 패스는 또한 작동해야처럼 보이지만, 같은 방법으로 실패하면 self.__dict__ = self을 설정하면

class DottableDict (dict): 

    def dotGet (self, attr): 
     return dict.__getitem__(self, attr) 

    def dotSet (self, attr, value): 
     return dict.__setitem__(self, attr, value) 

    def allowDotting (self, state=True): 
     if state: 
      self.__getattr__ = self.dotGet 
      self.__setattr__ = self.dotSet 
     else: 
      del self.__setattr__ 
      del self.__getattr__ 
+0

원하는 동작은 무엇입니까? – unutbu

+0

가끔 사전 [도트 - 액세스]를 사용하는 대신 인스턴스 [ 'foo']의 대안으로 instance.foo를 통해 dict 파생 인스턴스 값에 액세스하는 것을 좋아하지만 런타임시이 기능을 켜고 끌 수 있어야합니다. –

답변

6

, 다음 DICT가 자동으로 "dottable"이 될 것입니다. self.__dict__ = {}을 설정하여 "도트 - 어빌리티"를 끌 수 있습니다. 그러나 색인 생성을 통해 키 - 값 쌍에 계속 액세스 할 수 있습니다. 이 아이디어는 katrielalex's bio page에서 주로 제공 :

class DottableDict(dict): 
    def __init__(self, *args, **kwargs): 
     dict.__init__(self, *args, **kwargs) 
     self.__dict__ = self 
    def allowDotting(self, state=True): 
     if state: 
      self.__dict__ = self 
     else: 
      self.__dict__ = dict() 

d = DottableDict() 
d.allowDotting() 
d.foo = 'bar' 

print(d['foo']) 
# bar 
print(d.foo) 
# bar 

d.allowDotting(state=False) 
print(d['foo']) 
# bar 
print(d.foo) 
# AttributeError: 'DottableDict' object has no attribute 'foo'   

그러나 파이썬의 선을, 기억

one-- 과 그것을 할 바람직 하나 --obvious 방법이 있어야합니다.

DICT 액세스를위한 표준 문법에 자신을 제한함으로써, 당신은 자신과 다른 사람에 대한 가독성/유지 보수를 향상시킬 수 있습니다.


작동 원리 : 당신이 d.foo를 입력하면, 파이썬은 d.__dict__에 하나의 장소의 숫자에 'foo'을 찾습니다

. (또한 d.__class__.__dict__을보고 d.__class__.mro()에 나열된 모든 기지의 모든 __dict__ ... 속성 조회에 대한 자세한 내용은 excellent article by Shalabh Chaturvedi을 참조하십시오.

어쨌든 중요한 점은 d.__dict__에있는 모든 키 - 값 쌍에 점 표기법으로 액세스 할 수 있다는 것입니다.

사실은 우리가 d 자체에 d.__dict__을 설정하여 d의 키 - 값 쌍에 도트 액세스 할 수 있습니다 의미! 결국 d은 dict이며, d.__dict__은 dict-like 오브젝트를 기대합니다. 이것은 또한 메모리 효율적임을 주목하십시오. 우리는 어떤 키 - 값 쌍도 복사하지 않고 이미 존재하는 dict에 d.__dict__을 지시하는 것을 간략히하고 있습니다.

d.__dict__dict()에 할당함으로써 d의 키 - 값 쌍에 대한 도트 액세스를 효과적으로 해제합니다. (이것은 완전하게 비활성화 점 액세스하지 않습니다 -. 예를 들어 d.__class_.__dict__에서 키 - 값 쌍을 여전히 점 표기법을 통해 액세스 사실 다행하거나 다시 allowDotting 메소드를 호출 할 수 없을 것입니다 수 있습니다!)

이제 d에서 모든 키 - 값 쌍을 삭제하는지 궁금 할 것입니다. 내 대답은 아니오 야.

키 - 값 쌍은 __dict__ 속성에 저장되지 않습니다. 실제로 일반 dict에는 __dict__ 특성이 없습니다.따라서 d.__dict__ = {}을 설정하면 dict이 중립 조건으로 재설정됩니다. 우리는 너무

self.__dict__ = dict() 

del self.__dict__ 

insteaad을 사용했을 수 있습니다. 그러나 DottableDict__dict__ 속성이 부여되었으므로 DottableDict의 인스턴스에 항상 __dict__ 속성을 허용하는 것이 더 깨끗해 보입니다. 코멘트에서


당신은주의 :

단계 : 액세스를 설정, 액세스, '바'로 설정 d.foo을 해제 d.foo는 사방에서 사라졌다. allowDotting 동안 설정 한 같은 d.foo 같은

유지하기 위해 속성이 해제되어, 당신은 대체 DICT이있는 self.__dict__ 설정 한에 저장해야합니다.

class DottableDict(dict): 
    def __init__(self, *args, **kwargs): 
     dict.__init__(self, *args, **kwargs) 
     self['_attributes'] = dict() 
     self.allowDotting() 
    def allowDotting(self, state=True): 
     if state: 
      self.update(self['_attributes']) 
      self.__dict__ = self 
     else: 
      self.__dict__ = self['_attributes'] 

d = DottableDict() 
d.allowDotting(state=False) 
d.foo = 'bar' 
d.allowDotting(state=True) 
print(d.foo) 
# bar 
d.allowDotting(state=False) 
print(d.foo) 
# bar 
d.allowDotting(state=True) 
print(d.foo) 
# bar 

종래의 단일 밑줄로 시작하는 속성은 개인 구현 세부 정보로 이해됩니다. 개인 키 ('_attribute')를 사용하여 컨벤션을 확장합니다.

+0

이 코드는 내가 취해야 할 코드의 양과 훨씬 비슷합니다. 나는 파이썬이 어디에서 물건을 넣는 지 알아 내고 있고, 이해하지 못한다. 왜 'self .__ dict__'를 '{}'로 설정하면 attr 조회로 되돌릴 수 있습니까? –

+0

위의 설명을 약간 추가했습니다. – unutbu

+0

필자는'__dict__'가 도트 검색으로 검색되지 않았지만'class A (object) : pass'를 만든 다음'a = A()','setattr (a, 'foo' , 'bar')','print a.foo'와''bar ''를 뱉어 버렸기 때문에 내가 잘못한 것 같아요. 더 궁금한 점이 있지만 먼저 저에게 준 링크를 읽어 보겠습니다. 그 후에 남은 질문들에 대해서는 새 질문으로 물어볼 것입니다. 나는이 대답을 받아들입니다. 질문에 대답 할 때 가장 작고 유연하며, 내가 싸우고있는 모든 가장자리 조건을 제거합니다. 감사. –

관련 문제