整个访问字典时使用什么方法?

时间:2016-01-23 14:40:19

标签: python dictionary

我将dict子类化为具有易失性版本:在最后一次更新之后经过一段时间后,其值消失了(1)

import time
import collections

class Dict10min(dict):
    def __init__(self):
        super().__init__(self)
        self.expire = 0     # when to expire

    def __getitem__(self, item):
        if time.time() < self.expire:
            val = dict.__getitem__(self, item)
            return val
        else:
            # purging the dict
            self.clear()
            raise KeyError("key {item} does not exist anymore".format(item=item))

    def get(self, item, d=None):
        if time.time() < self.expire:
            try:
                val = dict.__getitem__(self, item)
            except KeyError:
                return d
            else:
                return val
        else:
            # purging the dict
            self.clear()
            return None

    def __setitem__(self, key, value):
        # set expire time at 10 minutes from now
        self.expire = time.time() + 5       # 5 seconds for tests, will be 600
        dict.__setitem__(self, key, value)

    # solution for update is from @johnrsharpe at http://stackoverflow.com/a/30242574/903011
    def update(self, other=None, **kwargs):
        if other is not None:
            for k, v in other.items() if isinstance(other, collections.Mapping) else other:
                self[k] = v
        for k, v in kwargs.items():
            self[k] = v

a = Dict10min()
a[1] = 2
time.sleep(6)
print(a.get(1))
a[3] = 4
print(a.get(1))

b = Dict10min()
b[1] = 2
time.sleep(6)
try:
    print(b[1])
except KeyError:
    print("entry does not exist anymore")
b[3] = 4
try:
    print(b[1])
except KeyError:
    print("entry does not exist anymore")

这正确输出

None
None
entry does not exist anymore
entry does not exist anymore

缺少的部分是处理整个Dict10min对象的部分:当整体访问它时,不使用__getitem__.get(),返回的是实际的字典的内容(而不是时间改变的版本)。

我应该在哪里挂钩以捕捉我的对象作为一个整体被访问的时刻(到return {})?

(1)代码在@TomDalton评论

之后更新

1 个答案:

答案 0 :(得分:1)

以下似乎对我有用。这是超级hacky!您需要为可能使用的任何其他“写入”方法添加挂钩。

import time


class ExpiringDict(dict):
    def __init__(self, expiry_secs, *args, **kwargs):
        self.expire = time.time() + expiry_secs
        self.expiry_secs = expiry_secs

        super(ExpiringDict, self).__init__(*args, **kwargs)

    def _reset_expire(self):
        self.expire = time.time() + self.expiry_secs

    def _check_expire(self):
        if time.time() > self.expire:
            self.clear()

    def __setitem__(self, key, value):
        self._reset_expire()
        return super(ExpiringDict, self).__setitem__(key, value)

    def update(self, *args, **kwargs):
        self._reset_expire()
        return super(ExpiringDict, self).update(*args, **kwargs)

    def __getitem__(self, *args, **kwargs):
        self._check_expire()
        return super(ExpiringDict, self).__getitem__(*args, **kwargs)

    def __getattribute__(self, name):
        attr = super(ExpiringDict, self).__getattribute__(name)
        if name not in {"_check_expire", "expire", "clear"}:
            self._check_expire()
        return attr

它通过了与你上面相同的测试。遗憾的是,__getitem__需要def __repr__(self, *args, **kwargs): self._check_expire() return dict.__repr__(self, *args, **kwargs) https://docs.python.org/3.5/reference/datamodel.html#special-lookup

因此,您可能需要添加其他方法。例如,如果你想像之前一样打印字典,你需要添加这样的repr:

$httpProvider

确保在打印前检查到期时间。