我正在运行 Python 2.7.10。
我需要拦截列表中的更改。我所说的“更改”是指在浅层意义上修改列表的任何内容(如果列表由相同顺序的相同对象组成,则不会更改,而不管这些对象的状态如何;否则,则更改)。我不需要找出列表是如何改变的,只需要知道它已经改变了。所以我只是确保我可以检测到它,并让基本方法完成它的工作。这是我的测试程序:
class List(list):
def __init__(self, data):
list.__init__(self, data)
print '__init__(', data, '):', self
def __getitem__(self, key):
print 'calling __getitem__(', self, ',', key, ')',
r = list.__getitem__(self, key)
print '-->', r
return r
def __setitem__(self, key, data):
print 'before __setitem__:', self
list.__setitem__(self, key, data)
print 'after __setitem__(', key, ',', data, '):', self
def __delitem__(self, key):
print 'before __delitem__:', self
list.__delitem__(self, key)
print 'after __delitem__(', key, '):', self
l = List([0,1,2,3,4,5,6,7]) #1
x = l[5] #2
l[3] = 33 #3
x = l[3:7] #4
del l[3] #5
l[0:4]=[55,66,77,88] #6
l.append(8) #7
Run Code Online (Sandbox Code Playgroud)
案例#1、#2、#3 和#5 按我的预期工作;#4、#6 和 #7 没有。该程序打印:
__init__( [0, 1, 2, 3, 4, 5, 6, 7] ): [0, 1, 2, 3, 4, 5, 6, 7]
calling __getitem__( [0, 1, 2, 3, 4, 5, 6, 7] , 5 ) --> 5
before __setitem__: [0, 1, 2, 3, 4, 5, 6, 7]
after __setitem__( 3 , 33 ): [0, 1, 2, 33, 4, 5, 6, 7]
before __delitem__: [0, 1, 2, 33, 4, 5, 6, 7]
after __delitem__( 3 ): [0, 1, 2, 4, 5, 6, 7]
Run Code Online (Sandbox Code Playgroud)
我对#7 并不感到非常惊讶:append可能以一种特别的方式实现。但是对于#4 和#6 我很困惑。该__getitem__文件说:“叫实行自行[关键]的评价对于序列类型,可接受的键应该是整数和。片的对象。” (我的重点)。而 for __setitem__:“与 for __getitem__()相同的注释”,我认为这key也可以是一个切片。
我的推理有什么问题?如有必要,我准备覆盖每个列表修改方法(附加、扩展、插入、弹出等),但是应该覆盖什么来捕获类似 #6 的内容?
我知道 等的存在__setslice__。但这些方法自 2.0 以来已被弃用......
嗯。我再次阅读了, 等的文档__getslice__,__setslice__我发现这个令人毛骨悚然的声明:
“(但是,CPython 中的内置类型目前仍然实现__getslice__()。因此,在实现切片时,您必须在派生类中覆盖它。)”
这是解释吗?这是说“好吧,这些方法已被弃用,但为了在 2.7.10 中实现与 2.0 中相同的功能,您仍然必须覆盖它们”?唉,那你为什么要弃用它们呢?未来将如何运作?是否有一个“列表”类 - 我不知道 - 我可以扩展并且不会带来这种不便?我真正需要覆盖什么才能确保我捕获每个列表修改操作?
您的问题是您正在继承一个内置函数,因此必须处理一些问题。在我深入研究这个问题之前,我将直接进入“更好”的答案:
未来将如何运作?是否有一个“列表”类 - 我不知道 - 我可以扩展并且不会带来这种不便?
是的,现代方法是使用 python 的Abstract Base Classes。您可以list通过使用 ABC 来避免子类化 builtin 时看到的这些丑陋的并发症。对于类似列表的东西,请尝试子类化MutableSequence:
from collections import MutableSequence
class MyList(MutableSequence):
...
Run Code Online (Sandbox Code Playgroud)
现在你应该只需要处理__getitem__和朋友的切片行为。
如果您想继续对 builtin 进行子类化list,请继续阅读...
您的猜测是正确的,您需要覆盖__getslice__和__setslice__。该语言参考解释了为什么你已经看到了:
但是,CPython 中的内置类型目前仍然实现
__getslice__(). 因此,在实现切片时,您必须在派生类中覆盖它。
请注意,l[3:7]将挂钩到__getslice__,而其他等效项l[3:7:]将挂钩到__getitem__。所以你必须同时处理切片......呻吟!
| 归档时间: |
|
| 查看次数: |
3151 次 |
| 最近记录: |