`list.__getslice__` 和 `list.__setslice__` 切片时发生了什么?

0 投票
1 回答
1497 浏览
提问于 2025-04-18 08:59

我正在尝试创建一个新的列表类,想要在原有的 list 基础上进行扩展,但我发现我的新列表表现得很奇怪,我觉得可能是 __setslice____getslice__ 这两个方法出了问题。我对 list 的修改并不明显,实际上是一些幕后操作;所以对用户来说,它应该和普通的 list 一样正常工作。

问题出现在用户想要 清空 列表的时候。我在 repl.it 上进行了一个测试,结果却很奇怪:

class IHateCoding(list):
    def __getslice__(self, *args):
        print 'get', args
        return super(IHateCoding, self).__getslice__(*args)
        
    def __setslice__(self, *args):
        print 'set', args
        super(IHateCoding, self).__setslice__(*args)

>>> l = IHateCoding()
>>> l.extend(xrange(5))
>>> l[:] = []
set (0, 2147483647, [])

这个 2147483647 的值是从哪里来的,为什么它会返回一个视图呢?

编辑:

我发现还有一个更奇怪的输出。有人能解释一下吗?

>>> l[:-1]
get (0, 2) #Expected `-1`

1 个回答

4

这就是 sys.maxint 的值,也就是“最大的整数”:

>>> sys.maxint
2147483647

因为你在切片的时候没有指定开始和结束的位置,所以开始是零,结束是“无穷大”,也就是Python能使用的最大整数。这个在文档中有说明,可以查看这里.

someList[:] 这个写法叫做切片,就像 someList[2:4] 一样。它只是一个没有指定开始和结束的切片。我不太明白你说的“视图”是什么意思。对列表进行的任何长度的切片都会返回那部分列表的副本。如果你不指定开始和结束,就会得到整个列表的副本,但这仍然只是一个切片操作。

不过要注意,someList[:] 作为一个表达式和作为赋值的 目标 是不同的,这正是你在做的事情。所以单独使用 someList[:] 会返回一个副本,但用 someList[:] = blah 进行切片赋值会直接修改列表的内容。再说一次,someList[:] = blah 是切片赋值,和 someList[2:5] 是一样的。给列表的切片赋值会改变那个切片的内容;如果切片是整个列表,那就会替换掉整个列表。

还要注意的是,每种类型的切片操作定义是不同的,所以在Numpy数组上切片和切片赋值的方式和在列表上是不一样的。列表没有真正等同于numpy的“视图”,后者实际上是对原始数组某部分的引用,这样对视图的修改也会影响到原始数组。

撰写回答