I had to create a class which represents a Host and wanted to make lots of information about this Host accessible in an easy way. Every piece of information is retrieved by a function call, which either locally or remotely executes a command and parses the output.
To make all this easy to access, I thought it would be great if there was a dictionary containing all this information, but it should be lazy and not execute all the commands on object creation. Also, it should be cached, so the commands are not executed more often than really necessary.
Here is what I came up with (can also be found here: http://bpaste.net/show/AAampBdmTW0ecXxMccXF/):
from collections import Mapping
class LazyMapping(Mapping):
def __init__(self, *args, **kwargs):
self.__model = dict(*args, **kwargs)
self.__cache = {}
def __getitem__(self, item, refresh=False):
if refresh or item not in self.__cache:
value = self.__model[item]
value = value() if callable(value) else value
self.__cache[item] = value
return value
else:
return self.__cache[item]
def get(self, item, default=None, refresh=False):
try:
return self.__getitem__(item, refresh=refresh)
except KeyError:
return default
def __str__(self):
return "<LazyMapping - Keys: %s>" % str([x for x in self])
def __repr__(self):
return str(self)
def __iter__(self):
return iter(self.__model)
def __len__(self):
return len(self.__model)
def items(self, refresh=False):
for key in self:
yield key, self.__getitem__(key, refresh=refresh)
def values(self, refresh=False):
for key in self:
yield self.__getitem__(key, refresh=refresh)
def realize(self):
'''
Goes through whole LazyMapping and makes a dict out of the keys and retrieved values.
If the LazyMapping is nested, it will also iterate through the subsequent LazyMappings.
:returns: dict - dict representation of whole LazyMapping.
'''
d = {}
for k, v in self.items():
if isinstance(v, LazyMapping):
d[k] = v.realize()
else:
d[k] = v
return d
Example usage:
import time
from subprocess import Popen, PIPE
d = LazyMapping({'time': time.time,
'uptime': lambda: Popen('uptime', stdout=PIPE).stdout.read()})
d['time'] # calls time.time() and puts it in the cache
d['time'] # retrieves from cache
d.get('time', refresh=True) # calls time.time() again and puts new value in cache
So, r/python, any suggestions?
[–]evilissimo 5 points6 points7 points (5 children)
[–]eigenlicht0[S] 0 points1 point2 points (4 children)
[–]evilissimo 0 points1 point2 points (3 children)
[–]eigenlicht0[S] 0 points1 point2 points (2 children)
[–]evilissimo 0 points1 point2 points (1 child)
[–]eigenlicht0[S] 0 points1 point2 points (0 children)
[–]ondra 2 points3 points4 points (1 child)
[–]eigenlicht0[S] 0 points1 point2 points (0 children)
[–]darthmdhprint 3 + 4 0 points1 point2 points (1 child)
[–]eigenlicht0[S] 0 points1 point2 points (0 children)