Python:尝试创建包含有限MRU条目的dict

2024-09-30 18:33:28 发布

您现在位置:Python中文网/ 问答频道 /正文

{ctypes>只为一个有限的mr}函数创建一个缓存项。代码如下:

from collections import OrderedDict

class MRUDict(OrderedDict):

    def __init__(self, capacity = 64):
        super().__init__()
        self.__checkAndSetCapacity(capacity)

    def capacity(self):
        return self.__capacity

    def setCapacity(self, capacity):
        self.__checkAndSetCapacity(capacity)
        for i in range(len(self) - capacity):
            self.__evict() # will execute only if len > capacity

    def __getitem__(self, key):
        value = super().__getitem__(key)
        # if above raises IndexError, next line won't execute
        print("Moving key {} to last i.e. MRU position".format(key))
        super().move_to_end(key)
        return value

    def __setitem__(self, key, value):
        if key in self:
            super().move_to_end(key)
        else: # new key
            if len(self) == self.__capacity:
                self.__evict()
        super().__setitem__(key, value)

    def __evict(self):
        key, value = self.popitem(last = False) # pop first i.e. oldest item
        print("Capacity exceeded. Evicting ({}, {})".format(key, value))

    def __checkAndSetCapacity(self, capacity):
        if not isinstance(capacity, int):
            raise TypeError("Capacity should be an int.")
        if capacity == 0:
            raise ValueError("Capacity should not be zero.")
        self.__capacity = capacity

。。。下面是测试代码:

^{pr2}$

现在从输出来看,我在实现__getitem__函数时有点幼稚,因为__repr__和{}(我猜,这两个函数分别调用__iter__,然后__getitem__)都会导致第一个项目作为MRU移动到最后一个项目,但无法继续,因为迭代器没有“next”项,因为它现在指向最后一个元素。但我不知道我能做些什么来解决这个问题。我应该重新实现__iter__?在

我不知道如何区分用户的调用__getitem__和内部调用。当然,解决方法是让用户使用一个find()方法来完成移动到结束的操作,但是我真的希望能够使用常规语法d[k]。在

请告知如何解决这个问题。谢谢!在


Tags: tokey函数selflenifvaluedef
1条回答
网友
1楼 · 发布于 2024-09-30 18:33:28

对于这样复杂的行为变化,研究^{} source code是值得的。在

实际的__iter__方法直接在内部结构(维护项目顺序的双链接列表)上循环。它永远不会直接使用__getitem__,而只是从链接列表返回键。在

你现在遇到的实际问题是,当循环时,你直接访问这些项目:

for k in d: print(k, d[k])

其中有一个d[k];正是访问将项目5从开始移动到结束。这将更新链接列表,因此当请求下一项时,curr.next引用现在是根,迭代停止。在

解决办法是不要那样做。添加一个专用方法来访问项目而不触发MRU更新。或者您可以重复使用dict.get(),例如:

^{pr2}$

您将使用.items()方法,OrderedDict重用^{}的{}方法,该方法返回一个^{}实例;请参见^{} source code。在

你必须改变这种行为:

from collections.abc import ItemsView


class MRUDictItemsView(ItemsView):
    def __contains__(self, item):
        key, value = item
        v = self._mapping.get(key, object())
        return v == value

    def __iter__(self):
        for key in self._mapping:
            yield (key, self._mapping.get(key))


class MRUDict(OrderedDict):
    # ...

    def items(self):
        return MRUDictItemsView(self)

您必须对.keys().values()方法执行相同的操作。在

相关问题 更多 >