赋值运算符左/右侧的不同切片行为

2024-05-27

作为一个来自 C++ 背景的 Python 新手,Python (3.4.x) 中的切片运算符对我来说看起来很荒谬。我只是不明白“特殊规则”背后的设计理念。让我解释一下为什么我说它“特别”。

一方面,根据 Stack Overflow 的回答here https://stackoverflow.com/questions/323689/python-list-slice-syntax-used-for-no-obvious-reason, 切片运算符创建列表或列表的一部分的(深层)副本,即一个新列表。该链接可能很旧(早于 python 3.4.x),但我刚刚通过以下 python 3.4.2 的简单实验确认了该行为:

words = ['cat', 'window', 'defenestrate']
newList = words[:] # new objects are created; a.k.a. deep copy
newList[0] = 'dog'

print(words) # ['cat' ...
print(newList) # ['dog' ...

另一方面,根据官方文档here https://docs.python.org/3.4/tutorial/introduction.html:

Assignment to slices is also possible, and this can even change the size of the list or clear it entirely:
>>>

>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # replace some values
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # now remove them
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # clear the list by replacing all the elements with an empty list
>>> letters[:] = []
>>> letters 
[]

显然,切片运算符[:]这里不做深拷贝。

从观察来看,似乎表明切片运算符在相对于赋值运算符位于左侧/右侧时会产生不同的行为。我不知道任何语言的操作员可以产生类似的行为。毕竟,运算符是一个函数,只是一个语法上的特殊函数,并且函数的行为应该是独立的,完全由其所有输入决定。

那么什么可以证明Python设计哲学中的这个“特殊规则”呢?

附:如果我的结论不正确的话,其实只有两种可能:

1、Python的切片‘运算符’实际上不是一个运算符,所以我的假设不成立---那么它是什么(‘切片运算符’[:])?

2、行为差异是由一些未被观察到的潜在因素造成的。切片运算符相对于赋值运算符的位置(左/右手侧)意外地与不同行为的观察共存。它们并不存在因果关系——那么造成行为差异的潜在因素是什么呢?


Python 运算符最好被视为语法糖"magic"方法;例如,x + y被评估为x.__add__(y)。以同样的方式:

  • foo = bar.baz变成foo = bar.__getattr__(baz);然而
  • bar.baz = foo变成bar.__setattr__(baz, foo);

蟒蛇“切片运算符” * a[b]被评估为:

  • a.__getitem__(b); or
  • a.__setitem__(b, ...);

取决于它位于任务的哪一侧;他们俩不完全是相同(另见赋值如何与 python 列表切片一起使用 https://stackoverflow.com/q/10623302/3001761)。写在“手写”, 所以:

>>> x = [1, 2, 3]
>>> x.__getitem__(slice(None))  # ... = x[:]
[1, 2, 3]
>>> x.__setitem__(slice(None), (4, 5, 6))  # x[:] = ...
>>> x
[4, 5, 6]

The 数据模型文档 https://docs.python.org/3/reference/datamodel.html更详细地解释这些方法(例如__getitem__ https://docs.python.org/3/reference/datamodel.html#object.__getitem__),你可以阅读文档上slice https://docs.python.org/3/library/functions.html#slice, too.


请注意,切片是一个浅拷贝,不是很深的,如下所示:

>>> foo = [[], []]
>>> bar = foo[:]
>>> bar is foo
False  # outer list is new object
>>> bar[0] is foo[0]
True  # inner lists are same objects
>>> bar[0].append(1)
>>> foo
[[1], []]

* 嗯,不是strictly an operator https://docs.python.org/3/reference/lexical_analysis.html#operators.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

赋值运算符左/右侧的不同切片行为 的相关文章

随机推荐