python a,b = b,一个实现?它与C++交换函数有什么不同?

Rio*_*aki 15 python algorithm

当我想尝试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方式编写这种交换函数?

sop*_*ros 7

这种行为确实与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)
  1. a[a[0]]从列表(值)的a[0]元素(等于2)中获取a0.
  2. a[0]2因此创建的元组是(0,2)
  3. (0,2)解压缩元组并0替换2列表(第0个元素).
  4. 现在,a[a[0]]可以读取:取第0个列表元素a(当前0),然后使用2from tuple unpacking 0替换该位置列表中的值(现在替换为2- 这使得操作看起来像对列表没有任何作用).

正如在更改顺序的答案中von Oak所建议的那样,因为从上面的第4点开始的步骤不会再次替换该值.


arg*_*rgo 5

要了解这一点,您需要使用实现内部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)

您可以看到前两个项目相同的输出字节代码.因此它不会交换