为什么Python3中的切片仍然是副本而不是视图?

为什么Python3中的切片仍然是副本而不是视图?,python,python-3.x,language-design,slice,Python,Python 3.x,Language Design,Slice,正如我在评论之后才注意到的那样,Python 3中的切片返回的是它们正在切片的内容的浅拷贝,而不是视图。为什么情况仍然如此?即使撇开numpy使用视图而不是副本进行切片不谈,dict.keys、dict.values、和dict.items都会在Python 3中返回视图,而且Python 3还有许多其他方面更倾向于使用迭代器,这似乎是一种朝着相似的方向发展的运动itertools确实有一个生成迭代切片的islice函数,但它比普通切片更受限制,并且不提供沿dict.keys或dict.valu

正如我在评论之后才注意到的那样,Python 3中的切片返回的是它们正在切片的内容的浅拷贝,而不是视图。为什么情况仍然如此?即使撇开numpy使用视图而不是副本进行切片不谈,
dict.keys
dict.values
、和
dict.items
都会在Python 3中返回视图,而且Python 3还有许多其他方面更倾向于使用迭代器,这似乎是一种朝着相似的方向发展的运动
itertools
确实有一个生成迭代切片的
islice
函数,但它比普通切片更受限制,并且不提供沿
dict.keys
dict.values
行的查看功能

同样,您可以使用对切片的赋值来修改原始列表,但切片本身是副本而不是视图,这是语言的一个矛盾方面,似乎违反了中所示的几个原则

也就是说,事实上你能做到

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

>>> a = [1, 2, 3, 4, 5]
>>> a[::2][0] = 0
>>> a
[0, 2, 3, 4, 5]
或者类似的

>>> 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]
似乎有些武断/不受欢迎

我知道它说“切片和扩展切片不会消失(即使
\uuu getslice\uuuuu
\uuuu setslice\uuuuu
API可能会被替换)也不会返回标准对象类型的视图的部分,但是链接的讨论没有提到为什么会做出使用视图进行切片的决定;事实上,在原始帖子中列出的建议中,对该具体建议的大多数评论似乎都是积极的

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

同样,您可以使用“指定给切片”来修改原始列表,但切片本身是副本,而不是视图

嗯。。那不太对;虽然我知道你是怎么想的。在其他语言中,切片赋值,类似于:

a[b:c] = d
相当于

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中,第一条语句实际上转换为:

a.__setitem__(slice(b, c), d)
也就是说,在python中,项赋值实际上被专门识别为具有特殊含义,与项查找和赋值分离;它们可能是无关的。这与python整体上是一致的,因为python没有像C/C++中的“左值”这样的概念;无法使赋值运算符本身过载;仅当赋值的左侧不是普通标识符时的特定情况

假设列表确实有视图;你试着用它:

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

在python以外的语言中,可能有一种方法可以将
yourList
插入
myList
,但在python中,由于名称
myView
显示为一个简单的标识符,因此它只能表示一个变量assignemnt;景色消失了

看来我发现了很多视图决策背后的原因,从线程开始(主要是关于字符串切片,但线程中至少有一封电子邮件提到了列表等可变对象),还有以下内容:


并在线程中跟踪电子邮件

看起来,对于基本Python来说,切换到这种风格的好处将大大超过由此产生的复杂性和各种不需要的边缘情况。哦,好吧

…然后,我开始考虑是否可以将当前使用的
slice
对象替换为一种可编辑的形式la
itertools.islice
,就像
zip
map
,等等。在Python3中,所有对象都返回iterables而不是列表,我开始意识到所有意想不到的行为和可能产生的问题。现在看来这可能是个死胡同

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

>>> a = [0, 0]
>>> a[:1] = [2, 3]
>>> a
[2, 3, 0]
我认为numpy的等价物应该是这样的:

>>> 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])
稍微复杂一点的情况:

>>> a = [1, 2, 3, 4]
>>> a[1:3] = [0, 0, 0]
>>> a
[1, 0, 0, 0, 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])

当然,上面的numpy示例并没有像常规Python列表扩展那样将结果存储在原始数组中。

我怀疑答案可能是视图不起作用,因为技术原因涉及Python列表的低级实现(针对速度进行了优化)。我将尝试查看源代码以支持此操作。但是,我们需要为我的列表[:]提供一个替代方案,执行“从副本导入浅拷贝”将非常糟糕。@utdemir一个替代方案是
列表(我的列表)
。它虽然不那么漂亮,但仍然相当简洁。@Wallacolo:它还允许混合列表和迭代器/生成器等(另一方面,它会将任何元组转换为列表,如果您想保持不变性,这可能并不可取)。实际上,我怀疑这也会导致在移植到Python 3时出现许多微妙的错误,即使2to3处理了它,Numpy至少通过使用
myView[:]=yourList
来解释裸露的标识符位。同样的事情也可以在常规Python中完成
a[:]
,是
a的语法糖。uuu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu(slice(None))
将返回
a
中所有项目的视图(或者如果
a
本身是一个视图,则返回
a
所引用的底层对象中的项目的视图),而不是默认情况下的
a
的浅层副本。这本身可能有点不和谐,但它似乎不像阿尔所说的那样