我想创建自己的集合,它具有python列表的所有属性,并且还知道如何在数据库中保存/加载自身.此外,我想使加载隐式和惰性,因为它不会在创建列表时发生,而是等到它第一次使用时.
有没有一种单一的__xxx__
方法,我可以覆盖上加载任何列表属性的第一次使用的列表(如len
,getitem
,iter
而不必重写他们... ...等)?
不完全是.对于模拟的东西其他比列表,有__getattribute__
,但不幸的是Python不认为像运营商x[y]
或者x(y)
是正好相同x.__getitem__(y)
或x.__call__(y)
.像这样的运算符是类的属性,而不是实例的属性,如下所示:
>>> class x(object): ... def __getattribute__(self, o): ... print o ... >>> x()[3] Traceback (most recent call last): File "", line 1, in TypeError: 'x' object does not support indexing
但是,您可以利用Python的动态特性来有效地消除这种区别.如果您主要关注的是保存自己的输入,并生成需要维护的代码较少,那么您可以执行以下操作:
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)
您可能不想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
.在collections
模块中找到的ABC ,其中MutableSequence
有一个,有两个原因:
允许您创建自己的类来模拟内部容器类型,以便它们可以在普通内置函数的任何位置使用.
用作参数isinstance
并issubclass
验证对象是否实现了必要的功能:
>>> isinstance([], MutableSequence) True >>> issubclass(list, MutableSequence) True
我们Monitored
班的工作方式如下:
>>> 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