6

データファイルを表すためにOrderedDict(Cpython、2.7.3)をサブクラス化しています。 __getitem__データファイルからフィールドを引き出し、以下に投稿したコードと同様に、現在のインスタンスに設定します。ここで、フィールドが辞書にあるか、ディスク上のファイルにあるかをオーバーライド__contains__して返すようにしますTrue。どちらの方法でも読み取ることができるからです。ただし、これにより、OrderedDictキーを検査する機能が損なわれるようです。

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
[]

dictclass = dict上記のコードを変更しても、機能しているように見えることに注意してください(次の出力が得られます)。

barbar
['bar']

私はひどく間違ったことをしていますか?

4

2 に答える 2

6

Foo.__contains__定義されていない場合

a['bar']

を呼び出しFoo.__getitem__、実行します

    self[key] = data

これはOrderedDict.__setitem__、を呼び出します。これは次のように定義されます。

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)

Foo.__contains__定義されていないので、

    if key not in self:

Trueです。したがって、キーはとに適切に追加されself.__rootますself.__map

Foo.__contains__が定義されている場合

    if key not in self:

Falseの場合。そのため、キーがとに適切に追加されていませself.__rootself.__map。 キーがすでに追加されていると考えるFoo.__contains__のに効果的な愚か者。OrderedDict.__setitem__'bar'


次のコードで遊ぶと便利だと思いました(とにprintステートメントを追加します__setitem____iter__

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']

Fooのサブクラスを作成し、その動作のほとんどを属性collections.MutableMappingに委任することで、この問題を回避できることに注意してください。OrderedDict

import collections
dictclass = collections.OrderedDict

class Foo(collections.MutableMapping):
    def __init__(self, *args, **kwargs):
        self._data = dictclass(*args, **kwargs)
    def __setitem__(self, key, value):
        self._data[key] = value
    def __delitem__(self, key):
        del self._data[key]
    def __iter__(self):
        return iter(self._data)
    def __len__(self):
        return len(self._data)

    def __getitem__(self,key):
        try:
            return self._data[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']
# barbar

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

__contains__定義されていても。

于 2013-03-09T22:39:24.693 に答える
2

あなたのコードを壊すのはor 'bar' in whateverです。削除すると、dictclass = dict言及した変更と同じように機能します。

__setitem__実装OrderedDictは次のとおりです。

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"と、条件はFalseになりますが、アイテムを挿入する前でもTrueになります。したがって、キーは追加されません。self.__rootこれは、で使用されOrderedDict.__iter__ます。

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"、この具象キーを値に返すことはできません。

于 2013-03-09T22:45:14.983 に答える