dictionary - Python: Trying to create a dict containing limited MRU entries -
i trying create dict
contains limited number of mru entries (for helping in caching output of costly c function call via ctypes). here code:
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) in range(len(self) - capacity): self.__evict() # execute if len > capacity def __getitem__(self, key): value = super().__getitem__(key) # if above raises indexerror, next line won't execute print("moving key {} 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 int.") if capacity == 0: raise valueerror("capacity should not zero.") self.__capacity = capacity
... , here testing code:
def printkeys(d): print("current keys in order:", tuple(d)) # here d means d.keys() print() mrudict import mrudict print("creating mrudict capacity 5.") d = mrudict(5) print("adding keys 0 7 values:") in range(8): d[i] = + 0.1 printkeys(d) print("calling str on object:") print(d) # test of default __repr__ (since __str__ same here) printkeys(d) print("accessing existing key 4:") print(4, d[4]) # test of __getitem__ printkeys(d) try: print("accessing non-existing key 20:") print(20, d[20]) # test of __getitem__ except: print("caught exception: key not exist.") printkeys(d) print("updating value of existing key 6:") d[6] = 6.6 # test of __setitem__ existing key printkeys(d) print("adding new key, value pair:") d[10] = 10.1 # test of __setitem__ non-existing key printkeys(d) print("testing presence of key 3:") print(3 in d) printkeys(d) print("trying loop on items:") k in d: print(k, d[k]) printkeys(d) print("trying loop on items:") k, v in d.items(): print(k, v) printkeys(d)
now output seems being kind of naive in implementing __getitem__
function because both __repr__
, for ... in
(which, i'm guessing here, call __iter__
, __getitem__
) causes first item moved last mru, cannot proceed further because there no "next" item iterator since points last element. not sure can fix situation. should reimplement __iter__
?
i not sure how distinguish between user's calling __getitem__
, internal call same. of course, workaround make user use find()
method move-to-end thing, i'd able use regular syntax d[k]
.
please advise on how fix this. thanks!
for complex changes of behaviour these, pays study ordereddict
source code.
the actual __iter__
method loops directly on internal structure, doubly linked list maintains item order. it'll never directly use __getitem__
, instead returning keys linked list.
the actual problem having directly accessing items while looping:
for k in d: print(k, d[k])
there d[k]
in there; that access moves item 5 start end. updates linked list, when asking next item curr.next
reference root , iteration stops.
the work-around not that. add dedicated method access items without triggering mru update. or re-use dict.get()
example:
>>> k in d: print(k, d.get(k)) ... 5 5.1 7 7.1 4 4.1 6 6.6 10 10.1
you will have problem .items()
method; ordereddict
reuses collections.abc.mutablemapping
's .items()
method, returns collections.abc.itemsview()
instance; see collections.abc
source code.
you'll have replace behaviour:
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): key in self._mapping: yield (key, self._mapping.get(key)) class mrudict(ordereddict): # ... def items(self): return mrudictitemsview(self)
you'd have same .keys()
, .values()
methods.
Comments
Post a Comment