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

发布于 2024-11-27 03:38:08 字数 1754 浏览 2 评论 0原文

正如我在评论 这个答案之后才注意到的那样,Python 中的切片3 返回它们正在切片的内容的浅副本而不是视图。为什么还是这样?即使不考虑 numpy 使用视图而不是副本进行切片,事实上, dict.keysdict.valuesdict.items 都Python 3 中的返回视图,以及 Python 3 的许多其他方面都致力于更多地使用迭代器,使得切片看起来似乎正在朝着变得相似的方向发展。 itertools 确实有一个 islice 函数,可以进行迭代切片,但它比普通切片更受限制,并且不提供类似于 dict.keys 的视图功能code> 或 dict.values

此外,您可以使用切片赋值来修改原始列表,但切片本身是副本而不是视图,这一事实是该语言的一个矛盾方面,并且似乎违反了 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 可能被替换)它们也不会返回标准对象类型的视图。”,但是链接的讨论没有提及为什么做出使​​用视图进行切片的决定;事实上,在原帖子中列出的建议中,对该具体建议的大多数评论似乎都是积极的。

是什么阻止了这样的事情在 Python 3.0 中实现,Python 3.0 专门设计为不严格向后兼容 Python 2.x,因此是在设计中实现此类更改的最佳时机,有什么可能会导致这种情况发生吗?在Python的未来版本中阻止它吗?

As I only now noticed after commenting on this answer, slices in Python 3 return shallow copies of whatever they're slicing rather than views. Why is this still the case? Even leaving aside numpy's usage of views rather than copies for slicing, the fact that dict.keys, dict.values, and dict.items all return views in Python 3, and that there are many other aspects of Python 3 geared towards greater use of iterators, makes it seem that there would have been a movement towards slices becoming similar. itertools does have an islice function that makes iterative slices, but that's more limited than normal slicing and does not provide view functionality along the lines of dict.keys or dict.values.

As well, the fact that you can use assignment to slices to modify the original list, but slices are themselves copies and not views, is a contradictory aspect of the language and seems like it violates several of the principles illustrated in the Zen of Python.

That is, the fact you can do

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

But not

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

or something like

>>> 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]

Seems somewhat arbitrary/undesirable.

I'm aware of http://www.python.org/dev/peps/pep-3099/ and the part where it says "Slices and extended slices won't go away (even if the __getslice__ and __setslice__ APIs may be replaced) nor will they return views for the standard object types.", but the linked discussion provides no mention of why the decision about slicing with views was made; in fact, the majority of the comments on that specific suggestion out of the suggestions listed in the original post seemed to be positive.

What prevented something like this from being implemented in Python 3.0, which was specifically designed to not be strictly backwards-compatible with Python 2.x and thus would have been the best time to implement such a change in design, and is there anything that may prevent it in future versions of Python?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦里寻她 2024-12-04 03:38:08

事实上,您可以使用切片赋值来修改原始列表,但切片本身是副本而不是视图。

嗯..这不太正确;虽然我知道你可能会怎么想。在其他语言中,切片赋值,类似于:

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)

这就是说,item 赋值实际上在 python 中被特殊识别为具有特殊含义,与 item 分开查找和赋值;它们可能不相关。这与整个Python是一致的,因为Python没有像C/C++中的“左值”这样的概念;没有办法重载赋值运算符本身;仅当赋值的左侧不是普通标识符时的特定情况。

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

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

在Python以外的语言中,可能有一种方法可以将yourList推入myList,但在Python中,因为名称myView 作为一个裸标识符出现,它只能表示一个变量 allocateemnt;视野消失了。

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

Hmm.. that's not quite right; although I can see how you might think that. In other languages, a slice assignment, something like:

a[b:c] = d

is equivalent to

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

But in python, the first statement is actually converted to this:

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

Which is to say that an item assignment is actually specially recognized in python to have a special meaning, separate from item lookup and assignment; they may be unrelated. This is consistent with python as a whole, because python doesn't have concepts like the "lvalues" found in C/C++; There's no way to overload the assignment operator itself; only specific cases when the left side of the assignment is not a plain identifier.

Suppose lists did have views; And you tried to use it:

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

In languages besides python, there might be a way to shove yourList into myList, but in python, since the name myView appears as a bare identifier, it can only mean a variable assignemnt; the view is lost.

緦唸λ蓇 2024-12-04 03:38:08

好吧,我似乎发现了视图决定背后的很多推理,按照以 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,就像< code>zip、map 等在 Python 3 中都返回可迭代对象而不是列表,我开始意识到所有意外的行为和可能由此产生的问题。看来目前这可能是一个死胡同。

从好的方面来说,numpy 的数组相当灵活,因此在可能需要这种事情的情况下,使用一维 ndarray 代替列表并不会太难。然而,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 列表扩展那样将结果存储在原始数组中。

Well it seems I found a lot of the reasoning behind the views decision, going by the thread starting with http://mail.python.org/pipermail/python-3000/2006-August/003224.html (it's primarily about slicing strings, but at least one e-mail in the thread mentions mutable objects like lists), and also some things from:

http://mail.python.org/pipermail/python-3000/2007-February/005739.html
http://mail.python.org/pipermail/python-dev/2008-May/079692.html and following e-mails in the thread

Looks like the advantages of switching to this style for base Python would be vastly outweighed by the induced complexity and various undesirable edge cases. Oh well.

...And as I then started wondering about the possibility of just replacing the current way slice objects are worked with with an iterable form a la itertools.islice, just as zip, map, etc. all return iterables instead of lists in Python 3, I started realizing all the unexpected behavior and possible problems that could come out of that. Looks like this might be a dead end for now.

On the plus side, numpy's arrays are fairly flexible, so in situations where this sort of thing might be necessary, it wouldn't be too hard to use one-dimensional ndarrays instead of lists. However, it seems ndarrays don't support using slicing to insert additional items within arrays, as happens with Python lists:

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

I think the numpy equivalent would instead be something like this:

>>> 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 slightly more complicated case:

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

versus

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

And, of course, the above numpy examples don't store the result in the original array as happens with the regular Python list expansion.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文