2013-03-09 2 views
6

나는 데이터 파일을 표현하기 위해 OrderedDict (Cpython, 2.7.3)를 서브 클래스 화하고있다. __getitem__은 데이터 파일에서 필드를 가져 와서 아래에 게시 한 코드와 비슷한 현재 인스턴스에 설정합니다. 필드가 사전에 있거나 디스크의 파일에 있다면 어느 한 방법으로 읽을 수 있기 때문에 지금 __contains__을 다시 지정하여 True을 반환하고 싶습니다. 그러나 이것은 열쇠를 검사하는 OrderedDict의 능력을 깨는 것 같습니다. 위의 코드에서 dictclass = dict를 변경하는 경우, 여전히 작동하는 것 같다 것을왜 __contains__를 재정 의하여 OrderedDict.keys를 해독합니까?

barbar 
[] 

주 (다음과 같은 출력을 제공) : 위의 코드를 실행하면

from collections import OrderedDict 

dictclass = OrderedDict 

class Foo(dictclass): 
    def __getitem__(self,key): 
     try: 
      return dictclass.__getitem__(self,key) 
     except KeyError: 
      pass 

     data = key*2 
     self[key] = data 
     return data 

    def __contains__(self,whatever): 
     return dictclass.__contains__(self,whatever) or 'bar' in whatever 

a = Foo() 
print a['bar'] 
print a.keys() 

,이 출력을 얻을 수 있습니다 .

barbar 
['bar'] 

끔찍한 일을하고 있습니까?

+0

나는 [출처] (http://hg.python.org/cpython/file/2.7/Lib/collections.py)를 읽고 있는데, 나는이 것을 알아 내기 힘들다. – mgilson

+0

나는 그렇게하고 있는데, 나는 어디에서 문제인지 생각한다 :'__setitem__'과'__iter__'을 한번보세요. –

+0

@A.Rodas - 예, 그것이 내가보고있는 곳입니다. 어쩌면 너무 피곤할 지 모르지만 나는 모든 논리를 똑바로 유지하는 데 어려움을 겪고있었습니다. – mgilson

답변

6

Foo.__contains__ 정의되지 않은 경우 : 012 이후

def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__): 
    'od.__setitem__(i, y) <==> od[i]=y' 
    # Setting a new item creates a new link at the end of the linked list, 
    # and the inherited dictionary is updated with the new key/value pair. 
    if key not in self: 
     root = self.__root 
     last = root[PREV] 
     last[NEXT] = root[PREV] = self.__map[key] = [last, root, key] 
    dict_setitem(self, key, value) 

이 이런 식으로 정의된다 OrderedDict.__setitem__를 호출

self[key] = data 

실행

a['bar'] 

통화 Foo.__getitem__,이 정의되어 있지 않습니다.

if key not in self: 

이 참입니다. 따라서 키는 self.__rootself.__map에 올바르게 추가됩니다. Foo.__contains__가을 정의

, 거짓 경우

if key not in self: 

. 따라서 키가 self.__rootself.__map에 올바르게 추가되지 않았습니다. Foo.__contains__ 효과적인 바보 OrderedDict.__setitem__은 이미 'bar' 키가 추가되었다고 생각합니다.


나는 것이 도움 (인쇄 __setitem__에서 제표 및 __iter__ 추가) 다음 코드로 연주 발견 : 당신이 Foo의 서브 클래스를 만들어이 문제를 방지 할 수 있습니다

from collections import OrderedDict 

dictclass = OrderedDict 

class Foo(dictclass): 
    def __getitem__(self,key): 
     try: 
      return dictclass.__getitem__(self,key) 
     except KeyError: 
      pass 

     data = key*2 
     self[key] = data 
     return data 

    def __contains__(self,whatever): 
     print('contains: {}'.format(whatever)) 
     return dictclass.__contains__(self,whatever) or 'bar' in whatever 

    def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__): 
     'od.__setitem__(i, y) <==> od[i]=y' 
     # Setting a new item creates a new link at the end of the linked list, 
     # and the inherited dictionary is updated with the new key/value pair. 
     print('key not in self: {}'.format(key not in self)) 
     if key not in self: 
      root = self._OrderedDict__root 
      last = root[PREV] 
      last[NEXT] = root[PREV] = self._OrderedDict__map[key] = [last, root, key] 
     dict_setitem(self, key, value) 

    def __iter__(self): 
     'od.__iter__() <==> iter(od)' 
     # Traverse the linked list in order. 
     NEXT, KEY = 1, 2 

     root = self._OrderedDict__root 
     curr = root[NEXT] 
     print('curr: {}'.format(curr)) 
     print('root: {}'.format(root)) 
     print('curr is not root: {}'.format(curr is not root)) 

     while curr is not root: 
      yield curr[KEY] 
      curr = curr[NEXT] 

a = Foo() 
print a['bar'] 
# barbar 

print a.keys() 
# ['bar'] 

공지 사항 collections.MutableMapping이고 대부분의 동작을 OrderedDict 속성에 위임합니다.

심지어 정의 __contains__

a = Foo() 
print a['bar'] 
# barbar 

print a.keys() 
# ['bar'] 

을 수득

.

+0

감사합니다. 그것입니다 - 나는'self .__ root'에 초점을 맞추는 데 너무 많은 시간을 보내고 어떻게 초기화되는지 생각합니다 - 생각 -'self .__ root = root = []; root [:] = [root, root, None]'무슨 일 이니 ?? : X – mgilson

+0

사물을 알아내는 나의 방법은 매우 낮습니다 - 일반적으로 많은 인쇄 문으로 이루어져 있습니다. :) – unutbu

2

코드를 깨뜨리는 것은 or 'bar' in whatever입니다. 제거하면 dictclass = dict 변경 사항과 같이 작동합니다.

OrderedDict__setitem__ 구현은 이것이다 :

def __setitem__(self, key, value, dict_setitem=dict.__setitem__): 
    'od.__setitem__(i, y) <==> od[i]=y' 
    # Setting a new item creates a new link at the end of the linked list, 
    # and the inherited dictionary is updated with the new key/value pair. 
    if key not in self: 
     root = self.__root 
     last = root[0] 
     last[1] = root[0] = self.__map[key] = [last, root, key] 
    return dict_setitem(self, key, value) 

그래서 self["bar"] = "barbar"으로, 조건이 거짓해야하지만, 심지어 항목을 삽입하기 전에 True입니다.

def __iter__(self): 
    'od.__iter__() <==> iter(od)' 
    # Traverse the linked list in order. 
    root = self.__root 
    curr = root[1]         # start at the first node 
    while curr is not root: 
     yield curr[2]        # yield the curr[KEY] 
     curr = curr[1]        # move to next node 
값을 검색하기위한 코드 반복자 사용하므로

self.__root이 콘크리트 키 값을 반환 할 수 없다 "bar" 포함하지 않는다 : 즉, 키 ISN은 'OrderedDict.__iter__에 사용되는 self.__root에 첨가 하였다.

+0

네, 여기 있습니다. 감사. +1. 물론, 내 코드에서 '또는'bar '는 무엇이든 더 복잡한 것이므로 제거하지 않기를 바란다. OrderedDict를 제대로 작동 시키려면 해킹하는 것이 너무 어려울 것 같습니다. 나는 정규 dict을 하위 클래스로 만들고 별도의'__order'리스트를 유지한다고 가정한다. – mgilson

+0

@mgilson : 어쩌면'Foo' *가 * be-a * OrderedDict 대신에'OrderedDict'를 갖도록할까요? – unutbu

+0

@unutbu - 맵핑 타입이므로 맵핑을 풀 수 있습니다. 직접 주문을 추적 할 수 있습니다. – mgilson

관련 문제