148 lines
4.7 KiB
Python
148 lines
4.7 KiB
Python
from threading import RLock
|
|
try:
|
|
from UserDict import DictMixin
|
|
except ImportError:
|
|
from collections import Mapping as DictMixin
|
|
|
|
|
|
_fill_lock = RLock()
|
|
|
|
|
|
class LazyDict(DictMixin):
|
|
"""Dictionary populated on first use."""
|
|
data = None
|
|
def __getitem__(self, key):
|
|
if self.data is None:
|
|
_fill_lock.acquire()
|
|
try:
|
|
if self.data is None:
|
|
self._fill()
|
|
finally:
|
|
_fill_lock.release()
|
|
return self.data[key.upper()]
|
|
|
|
def __contains__(self, key):
|
|
if self.data is None:
|
|
_fill_lock.acquire()
|
|
try:
|
|
if self.data is None:
|
|
self._fill()
|
|
finally:
|
|
_fill_lock_release()
|
|
return key in self.data
|
|
|
|
def __iter__(self):
|
|
if self.data is None:
|
|
_fill_lock.acquire()
|
|
try:
|
|
if self.data is None:
|
|
self._fill()
|
|
finally:
|
|
_fill_lock.release()
|
|
return iter(self.data)
|
|
|
|
def __len__(self):
|
|
if self.data is None:
|
|
_fill_lock.acquire()
|
|
try:
|
|
if self.data is None:
|
|
self._fill()
|
|
finally:
|
|
_fill_lock.release()
|
|
return len(self.data)
|
|
|
|
def keys(self):
|
|
if self.data is None:
|
|
_fill_lock.acquire()
|
|
try:
|
|
if self.data is None:
|
|
self._fill()
|
|
finally:
|
|
_fill_lock.release()
|
|
return list(self.data.keys())
|
|
|
|
|
|
class LazyList(list):
|
|
"""List populated on first use."""
|
|
def __new__(cls, fill_iter):
|
|
|
|
class LazyList(list):
|
|
_fill_iter = None
|
|
|
|
_props = (
|
|
'__str__', '__repr__', '__unicode__',
|
|
'__hash__', '__sizeof__', '__cmp__', '__nonzero__',
|
|
'__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__',
|
|
'append', 'count', 'index', 'extend', 'insert', 'pop', 'remove',
|
|
'reverse', 'sort', '__add__', '__radd__', '__iadd__', '__mul__',
|
|
'__rmul__', '__imul__', '__contains__', '__len__', '__nonzero__',
|
|
'__getitem__', '__setitem__', '__delitem__', '__iter__',
|
|
'__reversed__', '__getslice__', '__setslice__', '__delslice__')
|
|
|
|
def lazy(name):
|
|
def _lazy(self, *args, **kw):
|
|
if self._fill_iter is not None:
|
|
_fill_lock.acquire()
|
|
try:
|
|
if self._fill_iter is not None:
|
|
list.extend(self, self._fill_iter)
|
|
self._fill_iter = None
|
|
finally:
|
|
_fill_lock.release()
|
|
real = getattr(list, name)
|
|
setattr(self.__class__, name, real)
|
|
return real(self, *args, **kw)
|
|
return _lazy
|
|
|
|
for name in _props:
|
|
setattr(LazyList, name, lazy(name))
|
|
|
|
new_list = LazyList()
|
|
new_list._fill_iter = fill_iter
|
|
return new_list
|
|
|
|
|
|
class LazySet(set):
|
|
"""Set populated on first use."""
|
|
def __new__(cls, fill_iter):
|
|
|
|
class LazySet(set):
|
|
_fill_iter = None
|
|
|
|
_props = (
|
|
'__str__', '__repr__', '__unicode__',
|
|
'__hash__', '__sizeof__', '__cmp__', '__nonzero__',
|
|
'__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__',
|
|
'__contains__', '__len__', '__nonzero__',
|
|
'__getitem__', '__setitem__', '__delitem__', '__iter__',
|
|
'__sub__', '__and__', '__xor__', '__or__',
|
|
'__rsub__', '__rand__', '__rxor__', '__ror__',
|
|
'__isub__', '__iand__', '__ixor__', '__ior__',
|
|
'add', 'clear', 'copy', 'difference', 'difference_update',
|
|
'discard', 'intersection', 'intersection_update', 'isdisjoint',
|
|
'issubset', 'issuperset', 'pop', 'remove',
|
|
'symmetric_difference', 'symmetric_difference_update',
|
|
'union', 'update')
|
|
|
|
def lazy(name):
|
|
def _lazy(self, *args, **kw):
|
|
if self._fill_iter is not None:
|
|
_fill_lock.acquire()
|
|
try:
|
|
if self._fill_iter is not None:
|
|
for i in self._fill_iter:
|
|
set.add(self, i)
|
|
self._fill_iter = None
|
|
finally:
|
|
_fill_lock.release()
|
|
real = getattr(set, name)
|
|
setattr(self.__class__, name, real)
|
|
return real(self, *args, **kw)
|
|
return _lazy
|
|
|
|
for name in _props:
|
|
setattr(LazySet, name, lazy(name))
|
|
|
|
new_set = LazySet()
|
|
new_set._fill_iter = fill_iter
|
|
return new_set
|