Python 延迟列表

15 投票
5 回答
4350 浏览
提问于 2025-04-11 09:32

我想创建一个自己的集合,这个集合不仅具备Python列表的所有特点,还能知道怎么把自己保存到数据库里或者从数据库里加载出来。此外,我希望加载的过程是隐式和懒加载的,也就是说,它不是在创建列表的时候就发生,而是等到第一次使用的时候再加载。

有没有一个单独的__xxx__方法可以重写,这样在第一次使用任何列表属性(比如lengetitemiter等等)的时候就能加载列表,而不需要一个个重写这些方法呢?

5 个回答

7

其实不是完全一样。对于模拟列表以外的东西,可以用 __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 "<stdin>", line 1, in <module>
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(),但可以用一个合适的固定字符串列表来替代。

8

不是一个就够,而是五个就足够了:

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 模块中的抽象基类(ABCs),其中 MutableSequence 就是一个,存在的原因有两个:

  1. 让你可以创建自己的类,模仿内部容器类型,这样它们就可以在任何需要普通内置类型的地方使用。

  2. 可以作为 isinstanceissubclass 的参数,用来验证一个对象是否实现了必要的功能:

>>> 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

2

不,没有。

撰写回答