Package: ttlru-dict
LRU DictA fixed size dict like container which support ttl and evicts Least Recently
Used (LRU) items once size limit is exceeded or the ttl is exceeded.
LRU maximum capacity can be modified at run-time.This is a project forked fromhttps://github.com/amitdev/lru-dictand I added
ttl feature for it which makes it more suitable to be a cache. If you want to
know more about the origin work, please go to the above url.Installpipinstallttlru-dictoreasy_installttlru_dictUsageThis can be used to build a LRU cache with TTL. Usage is almost like a dict.fromttlruimportTTLRUimporttime# Create an TTLRU container that can hold 5 items, with default ttl = 1s# *NOTE* ttl is represented in nanosecondsl=TTLRU(5,ttl=1*1000000000)# add an item with a default ttl, in this case, it's 1000000000ns = 1 secondl[0]='0'# add an item with specified ttl, in this case it's 2 secondsl.set_with_ttl(1,'1',2*1000000000)print(l.items())# Would print [(1, '1'), (0, '0')]time.sleep(1)print(l.items())# Would print [(1, '1')], the first item expired.time.sleep(1)print(l.items())# Would print [], the second item also expired after 2 seconds.# ===================================================================# orher operations without ttll=TTLRU(5)print(l.peek_first_item(),l.peek_last_item())#return the MRU key and LRU key# Would print None Noneforiinrange(5):l[i]=str(i)print(l.items())# Prints items in MRU order# Would print [(4, '4'), (3, '3'), (2, '2'), (1, '1'), (0, '0')]print(l.peek_first_item(),l.peek_last_item())#return the MRU key and LRU key# Would print (4, '4') (0, '0')l[5]='5'# Inserting one more item should evict the old itemprint(l.items())# Would print [(5, '5'), (4, '4'), (3, '3'), (2, '2'), (1, '1')]l[3]# Accessing an item would make it MRUprint(l.items())# Would print [(3, '3'), (5, '5'), (4, '4'), (2, '2'), (1, '1')]# Now 3 is in frontprint(l.keys())# Can get keys alone in MRU order# Would print [3, 5, 4, 2, 1]dell[4]# Delete an itemprint(l.items())# Would print [(3, '3'), (5, '5'), (2, '2'), (1, '1')]print(l.get_size())# Would print 5l.set_size(3)print(l.items())# Would print [(3, '3'), (5, '5'), (2, '2')]print(l.get_size())# Would print 3print(l.has_key(5))# Would print Trueprint(2inl)# Would print Trueprint(l.get_stats())# Would print (1, 0)l.update({5:'0'})# Update an itemprint(l.items())# Would print [(5, '0'), (3, '3'), (2, '2')]l.clear()print(l.items())# Would print []defevicted(key,value):print("removing:%s,%s"%(key,value))l=TTLRU(1,callback=evicted)l[1]='1'l[2]='2'# callback would print removing: 1, 1l[2]='3'# doesn't call the evicted callbackprint(l.items())# would print [(2, '3')]dell[2]# doesn't call the evicted callbackprint(l.items())# would print []Notes and Technical DetailsFor more detailed information, please read the source code.about ttlttl = -1 means won't expire foreverttl is measured in nanoseconds. This is because Python's C-API_PyTime_GetSystemClockreturns timestamp as nanoseconds, I don't want to do extra conversion.When will ttl be checked?ttl is checked everytime when you try to access it, if expired, ttlru will remove the current item, and try to return a not expired item if possible:if you try to get a item likeresult = l['a'], if the item expired,Nonewill returned.if you try to get the first or the last item usingpeek_first_item()orpeek_last_item(), if the first or the last item expired, it will try the next item and return the first item that is not expired. if all items is expired, then returnNonekeys(),values()anditems()method will go through all the linked list and remove the expired items, then returns a list with not expired items.ttl is not checkd when you access the statistics data.thelen(l)will return count includes expired items. I think go through all the list to find not exist count is too expensive, maybe I can add another method to get the count of not expired items.What happened when insert an item?If the dict reached it's max size, then the last one will be removed. If there is an expired item but it is not the last one, then the expired item will still stay in the dict, only the last one will be removed. The reason is if I want to remove the expired one and keep the last one which is not expired, I have to use another data structure like a skip-table to keep the ttl order, which is not implemented in this version. For the other hand, the behavier above should be aTTL-Dict, not aTTL-LRU-Dict, Maybe I will write aTTL-Dictin the future.Different behavier against normal dictkeys(),values()anditems()returns a list, not a view object in Python3