赋值运算符左侧/右侧的不同切片行为
作为来自C ++背景的Python新手,Python(3.4.x)中的切片运算符对我来说似乎很荒谬.我只是不了解特殊规则"背后的设计理念.让我解释一下为什么我说这是特殊"的.
As a Python newbie coming from the C++ background, the slicing operator in Python (3.4.x) looks ridiculous to me. I just don't get the design philosophy behind the "special rule". Let me explain why I say it's "special".
一方面,根据堆栈溢出的答案在此处,切片运算符创建列表的一部分(深)副本或列表的一部分,即新列表.该链接可能较旧(早于python 3.4.x),但是我只是通过以下简单的python 3.4.2实验确认了该行为:
On the one hand, according to the Stack Overflow answer here, the slicing operator creates a (deep) copy of a list or part of the list, i.e. a new list. The link may be old (earlier than python 3.4.x), but I just confirmed the behavior with the following simple experiment with 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' ...
另一方面,根据官方文档此处:
On the other hand, according to the official documentation here:
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
[]
很显然,切片运算符[:]
不在此处进行深层复制.
Clearly, the slicing operator [:]
does not do a deep copy here.
根据观察结果,似乎表明切片运算符相对于赋值运算符位于左侧/右侧时会产生不同的行为.我不知道任何一种操作员都可以产生类似行为的语言.毕竟,运算符是一个函数,只是语法上特殊的函数,并且该函数的行为应是自包含的,完全由其所有输入确定.
From the observation it seems to suggest that the slicing operator produces different behavior when it's on left/right side with respect to the assignment operator. I do not know any language in which an operator could produce similar behavior. After all, an operator is a function, just a syntactically special function, and a function's behavior should be self-contained, purely determined by all of its inputs.
那么在Python设计哲学中有什么可以证明这一特殊规则"的合理性呢?
So what can justify this "special rule" in Python design philosophy?
P.S.如果我的结论不正确,那么实际上只有两种可能性:
P.S. If my conclusion is not correct, there are really only two possibilities:
1,Python的切片运算符"实际上不是运算符,因此我的假设不成立---那是什么(切片运算符" [:]
)?
1, Python's slicing 'operator' is actually not an operator, so my assumption does not hold --- then what is it (the 'slicing operator' [:]
)?
2,行为差异是由于未观察到某些潜在因素引起的.切片操作员相对于分配操作员的位置(左侧/右侧)与观察到的不同行为意外地并存.他们没有因果关系---那么导致行为差异的潜在因素是什么?
2, The difference in behavior is caused by some latent factor not observed. The slicing operator's location (left/right hand side) with respect to the assignment operator accidentally co-exists with the observation of different behavior. They do not have causality relationship --- then what is the latent factor that causes the difference in behavior?
对于魔术" 方法,最好将Python运算符视为语法糖.例如,x + y
被评估为x.__add__(y)
.用相同的方式:
Python operators are best considered as syntactic sugar for "magic" methods; for example, x + y
is evaluated as x.__add__(y)
. In the same way that:
-
foo = bar.baz
变为foo = bar.__getattr__(baz)
;而 -
bar.baz = foo
变为bar.__setattr__(baz, foo)
;
-
foo = bar.baz
becomesfoo = bar.__getattr__(baz)
; whereas -
bar.baz = foo
becomesbar.__setattr__(baz, foo)
;
Python 切片运算符" * a[b]
被评估为:
the Python "slicing operator" * a[b]
is evaluated as either:
-
a.__getitem__(b)
;或 -
a.__setitem__(b, ...)
;
-
a.__getitem__(b)
; or -
a.__setitem__(b, ...)
;
取决于它在作业的哪一边;两者不太相同相同(另请参见赋值如何与python列表切片一起使用) .因此写在"longhand" 中,
depending on which side of the assignment it's on; the two aren't quite the same (see also How assignment works with python list slice). Written out in "longhand", therefore:
>>> x = [1, 2, 3]
>>> x.__getitem__(slice(None)) # ... = x[:]
[1, 2, 3]
>>> x.__setitem__(slice(None), (4, 5, 6)) # x[:] = ...
>>> x
[4, 5, 6]
数据模型文档详细说明了这些方法(例如, __getitem__
),您可以阅读 slice
上的文档也是如此.
The data model documentation explains these methods in more detail (e.g. __getitem__
), and you can read the docs on slice
, too.
请注意,切片是一个浅拷贝,而不是一个深拷贝,如下所示:
Note that the slice is a shallow copy, not a deep one, as the following demonstrates:
>>> 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], []]
*嗯,不是严格地 一个 operator .
* Well, not strictly an operator.