__getitem__、__setitem__如何处理切片? [英] How do __getitem__, __setitem__, work with slices?

查看:42
本文介绍了__getitem__、__setitem__如何处理切片?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在运行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__如何处理切片?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆