10

我需要一个 pythonlist对象,它在插入时会自动检查表单的某些约束:“A 必须始终位于 B 之前”或“如果包含 C,则它必须始终位于最后”。

实现这一点的最简单/最快的方法是什么。显而易见的方法是覆盖列表数据类型的所有更改其内容的方法(appendextendinsert等),并验证在操作后约束是否仍然有效。只是这很乏味,因为有很多这些方法。有没有更简单的方法?

4

3 回答 3

5

我强烈建议从collections.MutableSequence抽象基类继承。缺点是它不会被识别为list(正如user4815162342指出的那样)的子类。但是,只要使用结果类的人做正确的事情(即使用鸭子类型或将抽象基类而不是具体类传递给 isinstance),这几乎无关紧要。

关于这一点的美妙之处在于,一旦您定义了以下方法,您就MutableSequence可以免费获得界面的其余部分。这是一个具体的子类MutableSequence,您可以将其用作进一步定制的模板。在您的情况下,您应该只需要自定义__init____setitem__insert__delitem__。其他所有内容都是根据这些定义的,因此将执行您插入的任何检查:

import collections
class MyList(collections.MutableSequence):
    def __init__(self, it=()):
        self._inner = list(it)
    def __len__(self):
        return len(self._inner)
    def __iter__(self):
        return iter(self._inner)
    def __contains__(self, item):
        return item in self._inner
    def __getitem__(self, index):
        return self._inner[index]
    def __setitem__(self, index, value):
        self._inner[index] = value
    def __delitem__(self, index):
        del self._inner[index]
    def __repr__(self):
        return 'MyList({})'.format(self._inner)
    def insert(self, index, item):
        return self._inner.insert(index, item)

几个简单的测试:

>>> ml = MyList('foo')
>>> ml
MyList(['f', 'o', 'o'])
>>> ml.append(5)
>>> ml
MyList(['f', 'o', 'o', 5])
>>> ml.reverse()
>>> ml
MyList([5, 'o', 'o', 'f'])
于 2012-11-18T19:23:47.510 回答
1

如果您的类型必须是 的子类型list,则您的选择是有限的。您必须继承并重写 mutator 方法,不要忘记特殊方法,例如__setitem__. 坏消息是没有办法强制使用这些方法。任何人,在任何时候,都可以调用:list.append(your_list, new_elem),并绕过你的append。更糟糕的是,Python 的实现在某些地方正是这样做的。(这在字典和元组中更常见。)

如果您的类型不需要继承 from list,请查看UserList和 at collections.MutableSequence

于 2012-11-18T18:59:01.520 回答
0

不要子类化list,代理它:覆盖__getattribute__以将所有调用传递给代理列表,然后检查您的约束。

于 2012-11-18T19:00:31.960 回答