为什么Python 3中的切片仍然是复制而不是视图?
正如我现在才注意到这个答案评论后,在Python 3中的切片返回他们切片,而不是视图的浅拷贝。 为什么还是这样? 即使不考虑numpy的视图使用情况而不是复制的切片, dict.keys
, dict.items
和dict.items
都会在Python 3中返回视图,Python 3还有很多其他的方面,迭代器,似乎会有一个切片变得相似的运动。 itertools
确实有一个islice
函数,可以进行迭代切片,但是这比正常的切片更有限,并且不提供沿着dict.keys
或dict.values
行的视图function。
同样,事实上你可以使用赋值来修改原始列表,但切片本身是拷贝而不是视图,这是这个语言的一个矛盾的方面,似乎违反了Python中的几个原则。
那就是,你可以做的事实
>>> 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]
似乎有点任意/不受欢迎。
我知道http://www.python.org/dev/peps/pep-3099/和它说的部分“切片和扩展切片不会消失(即使__getslice__
和__setslice__
API可能会被replace)也不会返回标准对象types的视图“,但是链接的讨论没有提到为什么做出关于视图切片的决定; 事实上,大部分对原文中所列build议的具体build议的评论似乎都是正面的。
是什么阻止了这样的东西在Python 3.0中实现,而Python 3.0是专门devise成不与Python 2.x严格向后兼容的,因此将是实现这种devise变更的最佳时机,在未来的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
这个名称显示为一个myView
标识符,它只能表示一个variables赋值; 视图丢失了。
好吧,看来我发现了很多的意见决定背后的推理,从http://mail.python.org/pipermail/python-3000/2006-August/003224.html开始的线程(主要是关于切分string,但是线程中至less有一封电子邮件提到了像列表这样的可变对象),还有一些来自:;
http://mail.python.org/pipermail/python-3000/2007-February/005739.html
http://mail.python.org/pipermail/python-dev/2008-May/079692.html及以下电子邮件在线程中;
看起来像基于Python的切换到这种风格的优势将远远超过诱导的复杂性和各种不希望的边缘情况。 好吧。
…然后,我开始想知道是否可以用当前的方式replace当前的slice
对象,迭代的forms是itertools.islice
,就像zip
, map
等所有在Python 3中返回iterables而不是列表一样我开始意识到所有出乎意料的行为和可能出现的问题。 看起来这可能是现在的死胡同。
从好的方面来说,numpy的数组是相当灵活的,所以在这种情况下可能是必要的,使用一维的ndarrays代替列表不会太困难。 但是,似乎ndarrays不支持使用切片在数组中插入额外的项目,就像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列表扩展那样将结果存储在原始数组中。