当我想尝试python版本时遇到了这个问题:https://leetcode.com/problems/first-missing-positive/discuss/17071/My-short-c++-solution-O( 1)-space- and -准时
我不确定为什么a[0], a[a[0]] = a[a[0]], a[0]这个不进行交换?
>>> nums
[2, 1, 0]
>>> a = [2,1,0]
>>> a[0], a[a[0]] = a[a[0]], a[0]
>>> a
[2, 1, 0]
>>> a[0]
2
>>> a[0],a[2] = a[2], a[0]
>>> a
[0, 1, 2]
Run Code Online (Sandbox Code Playgroud)
我的猜测是a,b = b,语法的实现类似于:
tmp = a[0] (tmp = 2)
a[0] = a[a[0]] (a[0] = a[2] = 0)
a[a[0]] = tmp (a[a[0]] = a[0] = tmp = 2)
Run Code Online (Sandbox Code Playgroud)
然后我检查了C++中swap函数的实现.我对C++一无所知,但看起来这个想法是一样的:http: //www.cplusplus.com/reference/algorithm/swap/
The behavior of these function templates is equivalent to:
template <class T> void swap (T& a, T& b)
{
T c(std::move(a)); a=std::move(b); b=std::move(c);
}
template <class T, size_t N> void swap (T (&a)[N], T (&b)[N])
{
for (size_t i = 0; i<N; ++i) swap (a[i],b[i]);
}
Run Code Online (Sandbox Code Playgroud)
我们有c = a,那么a = b和b = a那么为什么C++交换函数没有这个问题呢?以及如何以pythonic方式编写这种交换函数?
这种行为确实与Python评估类型表达式的方式有关
a,b=b,a
Run Code Online (Sandbox Code Playgroud)
事实上,Python所做的首先是通过创建元组来"准备"右侧的值(b,a).然后解压缩该元组并以相反的顺序分配给变量.
值得注意的是,临时元组是使用变量值(事实上的值副本)创建的,而不是对变量的引用(您可以在此处阅读有关传递值和引用之间的差异).
要使用您使用的引用类型(列表)分解示例:
a = [2,1,0]
a[0], a[a[0]] = a[a[0]], a[0]
Run Code Online (Sandbox Code Playgroud)
a[a[0]]从列表(值)的a[0]元素(等于2)中获取a值0.a[0]是2因此创建的元组是(0,2)(0,2)解压缩元组并0替换2列表(第0个元素).a[a[0]]可以读取:取第0个列表元素a(当前0),然后使用2from tuple unpacking 0替换该位置列表中的值(现在替换为2- 这使得操作看起来像对列表没有任何作用).正如在更改顺序的答案中von Oak所建议的那样,因为从上面的第4点开始的步骤不会再次替换该值.
要了解这一点,您需要使用实现内部dis.
首先考虑一个简单的交换函数:
from dis import dis
def swap(i, j):
i, j = j, i
dis(swap)
Run Code Online (Sandbox Code Playgroud)
输出字节代码:
4 0 LOAD_FAST 1 (j)
2 LOAD_FAST 0 (i)
4 ROT_TWO
6 STORE_FAST 0 (i)
8 STORE_FAST 1 (j)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
你可以看到有ROT_TWO这意味着
交换两个最顶层的堆栈项.
这ROT_TWO主要负责交换.
现在回答你的问题:
让我们举一个有效的例子:
from dis import dis
def swap():
a = [2, 1]
a[0], a[1] = a[1], a[0]
dis(swap)
Run Code Online (Sandbox Code Playgroud)
输出字节代码:
4 0 LOAD_CONST 1 (2)
2 LOAD_CONST 2 (1)
4 BUILD_LIST 2
6 STORE_FAST 0 (a)
5 8 LOAD_FAST 0 (a)
10 LOAD_CONST 2 (1)
12 BINARY_SUBSCR
14 LOAD_FAST 0 (a)
16 LOAD_CONST 3 (0)
18 BINARY_SUBSCR
20 ROT_TWO
22 LOAD_FAST 0 (a)
24 LOAD_CONST 3 (0)
26 STORE_SUBSCR
28 LOAD_FAST 0 (a)
30 LOAD_CONST 2 (1)
32 STORE_SUBSCR
34 LOAD_CONST 0 (None)
36 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
输出字节代码与我们在简单交换功能时的代码类似.
但是当代码改变时:
from dis import dis
def swap():
a = [1, 0]
a[0], a[a[0]] = a[a[0]], a[0]
dis(swap)
swap()
Run Code Online (Sandbox Code Playgroud)
输出是
4 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (0)
4 BUILD_LIST 2
6 STORE_FAST 0 (a)
5 8 LOAD_FAST 0 (a)
10 LOAD_FAST 0 (a)
12 LOAD_CONST 2 (0)
14 BINARY_SUBSCR
16 BINARY_SUBSCR
18 LOAD_FAST 0 (a)
20 LOAD_CONST 2 (0)
22 BINARY_SUBSCR
24 ROT_TWO
26 LOAD_FAST 0 (a)
28 LOAD_CONST 2 (0)
30 STORE_SUBSCR
32 LOAD_FAST 0 (a)
34 LOAD_FAST 0 (a)
36 LOAD_CONST 2 (0)
38 BINARY_SUBSCR
40 STORE_SUBSCR
42 LOAD_CONST 0 (None)
44 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
您可以看到前两个项目相同的输出字节代码.因此它不会交换