Python惰性列表
我想创建我自己的集合,它具有python列表的所有属性,并且知道如何将自身保存/加载到数据库中。我还想使加载隐式且懒惰,因为它不会在创建列表时发生,而是等待它第一次使用Python惰性列表,python,Python,我想创建我自己的集合,它具有python列表的所有属性,并且知道如何将自身保存/加载到数据库中。我还想使加载隐式且懒惰,因为它不会在创建列表时发生,而是等待它第一次使用 是否有一个\uuuxxx\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu>方法可以在首次使用任何列表属性(例如len、getitem、、、。但是,Python并不认
是否有一个
\uuuxxx\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu>方法可以在首次使用任何列表属性(例如len
、getitem
、、、。但是,Python并不认为操作符如<代码> x[y] 或<代码> x(y)< /代码>完全与<代码> x.py-gigTimeTyy(y)或<代码> x.py-Calasyy(y)完全相同。这样的运算符是类的属性,而不是实例的属性,如您在此处所见:
>>> class x(object):
... def __getattribute__(self, o):
... print o
...
>>> x()[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'x' object does not support indexing
您可能不想在现实生活中使用dir()
,但是可以使用一个合适的固定字符串列表作为替代。不是一个字符串,但5个就足够了:
from collections import MutableSequence
class Monitored(MutableSequence):
def __init__(self):
super(Monitored, self).__init__()
self._list = []
def __len__(self):
r = len(self._list)
print "len: {0:d}".format(r)
return r
def __getitem__(self, index):
r = self._list[index]
print "getitem: {0!s}".format(index)
return r
def __setitem__(self, index, value):
print "setitem {0!s}: {1:s}".format(index, repr(value))
self._list[index] = value
def __delitem__(self, index):
print "delitem: {0!s}".format(index)
del self._list[index]
def insert(self, index, value):
print "insert at {0:d}: {1:s}".format(index, repr(value))
self._list.insert(index, value)
检查某个东西是否实现了整个列表接口的正确方法是检查它是否是MutableSequence
的子类。在集合
模块中找到的ABC,其中可变序列
是其中之一,其存在有两个原因:
允许您创建自己的类来模拟内部容器类型,以便它们可以在任何普通内置类型的地方使用
要用作isinstance
和IsubClass
的参数,以验证对象是否实现了必要的功能:
我们的监控
类的工作原理如下:
class override(object):
def __init__(self, methodName):
self.methodName = methodName
def __get__(self, oself, cls):
oself._load(self.methodName)
return getattr(super(oself.__class__, oself), self.methodName)
class LazyList(list):
def _load(self, name):
print 'Loading data for %s...' % (name,)
for methodName in set(dir(list)) - set(dir(object)):
locals()[methodName] = override(methodName)
>>> m = Monitored()
>>> m.append(3)
len: 0
insert at 0: 3
>>> m.extend((1, 4))
len: 1
insert at 1: 1
len: 2
insert at 2: 4
>>> m.l
[3, 1, 4]
>>> m.remove(4)
getitem: 0
getitem: 1
getitem: 2
delitem: 2
>>> m.pop(0) # after this, m.l == [1]
getitem: 0
delitem: 0
3
>>> m.insert(0, 4)
insert at 0: 4
>>> m.reverse() # After reversing, m.l == [1, 4]
len: 2
getitem: 1
getitem: 0
setitem 0: 1
setitem 1: 4
>>> m.index(4)
getitem: 0
getitem: 1
1
>>>m=受监控()
>>>m.1(3)
len:0
在0:3插入
>>>m.extend((1,4))
莱恩:1
以1:1插入
蓝:2
在2:4插入
>>>硕士
[3, 1, 4]
>>>m.删除(4)
getitem:0
获取项目:1
获取项目:2
交货期:2
>>>m.pop(0)#在此之后,m.l==[1]
getitem:0
交货期:0
3.
>>>m.插入(0,4)
在0:4插入
>>>m.reverse()#反转后,m.l==[1,4]
蓝:2
获取项目:1
getitem:0
集合项0:1
设定项目1:4
>>>m.index(4)
getitem:0
获取项目:1
1.
没有一种方法。你必须重新定义它们中的很多。可变序列似乎是实现这一点的现代方式。下面是一个使用Python 2.4+的版本:
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
寻找隐藏的dwiw方法,嗯?“做我想做的”。这就是我要说的一切…:)@如果在_load函数中定义了getItem,那么粘贴的代码将起作用,您应该调用list.(self,…)来添加数据以防止递归加载。示例:list.append(self,value)是否有必要链接到粘贴站点?另外,我不太明白你的答案的第一部分:你的意思是定义uu getitem_uuuu()?谢谢你的编辑,hop,我不知道为什么要链接到粘贴站点。我明确地不打算定义\uuuu getitem\uuuu
;答案的这一部分的全部要点是说明没有一个可以重写的双下划线方法,您必须覆盖其中的许多。的2.x文档表示,返回的词典内容不应该修改——那么使用这种技术是一个好主意吗?@Andrew通过将索引的格式字符串从“{0:d}”更改为“{0!s}”来修复此问题
在三种方法中,index
可能是一个切片对象。我发布了一篇关于我发现的一些奇怪行为的文章,你介意看一下吗?
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