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

Popular posts from this blog

how to proxy from https to http with lighttpd -

android - Automated my builds -

python - Flask migration error -