为什么python 3中的切片仍然是复制的而不是视图?

Why are slices in Python 3 still copies and not views?

正如我在评论完这个答案后才注意到的,python3中的切片返回了它们正在切片的内容的浅拷贝,而不是视图。为什么还是这样?即使不考虑numpy对视图的使用而不是用于切片的副本,事实上dict.keysdict.valuesdict.items都返回了python3中的视图,并且python3还有许多其他面向更大程度使用迭代器的方面,使得似乎有一种朝着切片变得相似的趋势。itertools确实有一个生成迭代切片的islice函数,但这比正常切片更为有限,并且不提供沿dict.keysdict.values线的视图功能。

此外,您可以使用赋值来切片修改原始列表,但切片本身是副本,而不是视图,这是语言的一个矛盾方面,似乎违反了Python禅中说明的几个原则。

也就是说,事实上你可以

1
2
3
4
>>> a = [1, 2, 3, 4, 5]
>>> a[::2] = [0, 0, 0]
>>> a
[0, 2, 0, 4, 0]

但不是

1
2
3
4
>>> a = [1, 2, 3, 4, 5]
>>> a[::2][0] = 0
>>> a
[0, 2, 3, 4, 5]

或者类似的

1
2
3
4
5
6
7
8
9
>>> a = [1, 2, 3, 4, 5]
>>> b = a[::2]
>>> b
view(a[::2] -> [1, 3, 5])   # numpy doesn't explicitly state that its slices are views, but it would probably be a good idea to do it in some way for regular Python
>>> b[0] = 0
>>> b
view(a[::2] -> [0, 3, 5])
>>> a
[0, 2, 3, 4, 5]

似乎有些武断/不可取。

我知道http://www.python.org/dev/peps/pep-3099/和它所说的"切片和扩展切片不会消失(即使可以替换__getslice____setslice__API),它们也不会返回标准对象类型的视图。"但是链接的讨论没有提到为什么要对视图进行切片的决定。;事实上,在原帖子所列建议中,对该具体建议的大多数评论似乎都是积极的。

是什么阻止了类似这样的事情在Python3.0中实现,而Python3.0是专门设计为不与Python2.x严格向后兼容的,因此是实现这种设计更改的最佳时机,在将来的Python版本中有什么可能阻止它实现的吗?


As well, the fact that you can use assignment to slices to modify the original list, but slices are themselves copies and not views.

隐马尔可夫模型。。这不太对,尽管我能看出你是怎么想的。在其他语言中,切片分配,类似于:

1
a[b:c] = d

等于

1
2
tmp = a.operator[](slice(b, c)) # which returns some sort of reference
tmp.operator=(d)        # which has a special meaning for the reference type.

但是在python中,第一条语句实际上被转换为:

1
a.__setitem__(slice(b, c), d)

也就是说,在python中,一个项目分配实际上是被特别地识别出来的,具有特殊的意义,与项目查找和分配分开;它们可能是无关的。这与Python作为一个整体是一致的,因为Python没有类似于C/C++中的"LVales"的概念;无法赋值赋值运算符本身;只有特定的情况,当赋值的左边不是一个简单的标识符时。

假设列表确实有视图,并且您尝试使用它:

1
2
3
myView = myList[1:10]
yourList = [1, 2, 3, 4]
myView = yourList

在除python之外的语言中,可能有一种方法可以将yourList推入myList中,但是在python中,由于名称myView显示为一个裸标识符,因此它只能表示一个变量assignemnt;视图将丢失。


好吧,看起来我发现了很多视图决策背后的原因,从http://mail.python.org/pipermail/python-3000/2006-august/003224.html开始(它主要是关于字符串切片,但线程中至少有一封电子邮件提到了列表等可变对象),以及以下内容:

http://mail.python.org/pipermail/python-3000/2007-2月/005739.htmlhttp://mail.python.org/pipermail/python-dev/2008-may/079692.html以及线程中的以下电子邮件

看起来,为基本python切换到这种风格的优势将被所引起的复杂性和各种不需要的边缘情况大大抵消。哦,好吧。

…然后,当我开始考虑是否可以用一个可迭代的形式来代替当前的方法来处理slice对象时,就像zipmap等一样,所有返回的都是ITerables而不是python3中的列表,我开始意识到所有可能会导致这就是问题所在。看来现在这可能是个死胡同。

另一方面,numpy的数组相当灵活,因此在需要这种类型的情况下,使用一维的ndarrays而不是列表并不难。但是,Ndarrays似乎不支持使用切片在数组中插入其他项,就像在python列表中那样:

1
2
3
4
>>> a = [0, 0]
>>> a[:1] = [2, 3]
>>> a
[2, 3, 0]

我认为麻木的等价物应该是这样的:

1
2
3
4
>>> a = np.array([0, 0])  # or a = np.zeros([2]), but that's not important here
>>> a = np.hstack(([2, 3], a[1:]))
>>> a
array([2, 3, 0])

稍微复杂一点的情况:

1
2
3
4
>>> a = [1, 2, 3, 4]
>>> a[1:3] = [0, 0, 0]
>>> a
[1, 0, 0, 0, 4]

对战

1
2
3
4
>>> a = np.array([1, 2, 3, 4])
>>> a = np.hstack((a[:1], [0, 0, 0], a[3:]))
>>> a
array([1, 0, 0, 0, 4])

当然,上面这些麻木的示例并不像常规的python列表扩展那样将结果存储在原始数组中。