正如我在评论this answer后才注意到的那样,Python 3中的切片返回了他们正在切片而不是视图的浅层副本。为什么仍然如此?即使不考虑numpy对视图的使用而不是切片的副本,dict.keys
,dict.values
和dict.items
都会在Python 3中返回视图,而且还有许多其他方面的Python 3更倾向于使用迭代器,这似乎会使切片变得相似。 itertools
确实有一个islice
函数可以生成迭代切片,但这比普通切片更有限,并且不提供dict.keys
或dict.values
行的视图功能。
同样,你可以使用赋值给切片来修改原始列表,但切片本身就是副本而不是视图,这是语言的一个矛盾方面,似乎违反了{{}中所示的几个原则。 3}}
即你可以做的事实
>>> 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]
似乎有点武断。
我知道the Zen of Python以及它所说的部分“切片和扩展切片不会消失(即使__getslice__
和__setslice__
API可能被替换)也不是他们是否会返回标准对象类型的视图。“但是链接的讨论没有提到为什么做出关于切片视图的决定;事实上,原始帖子中列出的建议中对该特定建议的大多数评论似乎是积极的。
什么阻止这样的东西在Python 3.0中实现,Python 3.0专门设计为不与Python 2.x严格向后兼容,因此可能是实现这种设计变更的最佳时机,并且在那里任何可能在未来的Python版本中阻止它的东西?
答案 0 :(得分:10)
嗯..那不太对;虽然我可以看到你怎么想。在其他语言中,切片分配,例如:同样,你可以使用赋值给切片来修改原始列表,但切片本身就是副本而不是视图。
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 ++中找到的“lvalues”这样的概念;没有办法重载赋值运算符本身;仅当赋值的左侧不是普通标识符时的特定情况。
假设列表 有视图;你试图使用它:
myView = myList[1:10]
yourList = [1, 2, 3, 4]
myView = yourList
在python之外的语言中,可能有一种方法可以将yourList
推送到myList
,但是在python中,因为名称myView
显示为一个简单的标识符,它只能表示变量赋值;视图丢失了。
答案 1 :(得分:2)
好吧,似乎我发现了很多关于视图决策背后的推理,从以http://mail.python.org/pipermail/python-3000/2006-August/003224.html开始的线程开始(主要是关于切片字符串,但线程中至少有一封电子邮件提到可变对象,如列表),还有一些来自:
http://mail.python.org/pipermail/python-3000/2007-February/005739.html
http://mail.python.org/pipermail/python-dev/2008-May/079692.html并在帖子中关注电子邮件
看起来,基本Python切换到这种风格的优势将被诱导的复杂性和各种不良边缘情况大大超过。哦,好吧。
...然后当我开始想知道只是替换当前方式的可能性slice
对象使用可迭代的形式la itertools.islice
,就像zip
一样, map
等都返回迭代,而不是Python 3中的列表,我开始意识到所有意外行为和可能出现的问题。看起来这可能是现在的死胡同。
从好的方面来说,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列表扩展那样将结果存储在原始数组中。