问题描述
我正在运行Python2.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
案例#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]
我对#7并不感到非常惊讶:append
可能是以特殊的方式实现的。但对于4号和6号,我感到困惑。__getitem__
文档中写道:"调用来实现对self[key]的求值。对于序列类型,接受的key应该是整型和切片对象。"(My Emphasys)。对于__setitem__
:"与__getitem__
()"相同的注释,我认为这意味着key
也可以是一个切片。
我的推理有什么问题?如有必要,我准备重写每个列表修改方法(append、Extended、Insert、Pop等),但应该重写什么才能捕获类似#6的内容?
我知道__setslice__
等的存在,但这些方法从2.0开始就不再推荐使用...
嗯。我再次阅读了__getslice__
、__setslice__
等的文档,我发现了这个令人毛骨悚然的声明:
"(但CPython中的内置类型目前仍实现__getslice__()
,因此在实现分片时必须在派生类中重写)"
这就是解释吗?这句话是不是"好吧,方法已经过时了,但是为了在2.7.10中实现与在2.0中相同的功能,您仍然必须覆盖它们"?唉,那你为什么要反对他们呢?未来的事情将如何运作?有没有一个我不知道的"列表"类,我可以扩展,并且不会带来这种不便?我真正需要重写什么才能确保捕获每个列表修改操作?
推荐答案
问题是您正在对内建子类化,因此必须处理一些皱纹。在我深入探讨这个问题之前,我将直接介绍一下现代方法:
是的,有stdlibAbstract Base Classes。您可以通过使用ABC来避免对内建子类化未来的事情将如何运作?是否有我不知道的列表&类可以扩展并且不会带来这种不便?
list
造成的难看的复杂情况。对于类似列表的内容,请尝试子类化MutableSequence
:
from collections import MutableSequence
class MyList(MutableSequence):
...
现在您应该只需要处理__getitem__
和好友的切片行为。
如果您想推进内建子类化list
,请继续阅读...
__getslice__
和__setslice__
。language reference explains why,您已经看到:
然而,CPython中的内置类型目前仍然实现__getslice__()
。因此,在实现切片时,您必须在派生类中重写它。
请注意,l[3:7]
将挂钩到__getslice__
,而其他等价的l[3:7:]
将挂钩到__getitem__
,因此您必须处理在这两种方法中接收切片的可能性...呻吟!
这篇关于__getitem__、__setitem__如何处理切片?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!