`list.__getslice__` 和 `list.__setslice__` 切片时发生了什么?
我正在尝试创建一个新的列表类,想要在原有的 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 个回答
这就是 sys.maxint
的值,也就是“最大的整数”:
>>> sys.maxint
2147483647
因为你在切片的时候没有指定开始和结束的位置,所以开始是零,结束是“无穷大”,也就是Python能使用的最大整数。这个在文档中有说明,可以查看这里.
someList[:]
这个写法叫做切片,就像 someList[2:4]
一样。它只是一个没有指定开始和结束的切片。我不太明白你说的“视图”是什么意思。对列表进行的任何长度的切片都会返回那部分列表的副本。如果你不指定开始和结束,就会得到整个列表的副本,但这仍然只是一个切片操作。
不过要注意,someList[:]
作为一个表达式和作为赋值的 目标 是不同的,这正是你在做的事情。所以单独使用 someList[:]
会返回一个副本,但用 someList[:] = blah
进行切片赋值会直接修改列表的内容。再说一次,someList[:] = blah
是切片赋值,和 someList[2:5]
是一样的。给列表的切片赋值会改变那个切片的内容;如果切片是整个列表,那就会替换掉整个列表。
还要注意的是,每种类型的切片操作定义是不同的,所以在Numpy数组上切片和切片赋值的方式和在列表上是不一样的。列表没有真正等同于numpy的“视图”,后者实际上是对原始数组某部分的引用,这样对视图的修改也会影响到原始数组。