a,b = b,a in python vs std::swap() in C++

a,b = b,a in python vs std::swap() in C++

本文关键字:in swap C++ vs python std      更新时间:2023-10-16

我知道a,b = b,a基本上是在分配一个元组(a,b)另一个元组(b,a)的值。从本质上讲,这是将值从a交换到b以及从b交换到a。因此,导致"交换"。

这是C++中swap()函数的功能。

从研究中,我看到C++的swap()函数使用第三个临时变量来执行交换。我一直无法找到如何在 python 中实现a,b = b,a

如何实施a,b = b,a

python是否也使用第三个临时变量?如果没有,它是如何工作的?

两种操作在速度方面如何比较?我猜如果python也使用第三个变量,执行时间的差异是由于python被解释造成的。

编辑:所有的答案都很棒,但社区似乎认为Sapan是最好的答案。也感谢a_guest,虽然没有发布答案,但在评论中给了我们很多信息。另外:每个人似乎都同意swap()更快,因为它C++。我不一定同意这一点。如果作为冻结的二进制文件运行,Python 可以非常快。

对于元组赋值,Python 直接使用堆栈结构:

>>> import dis
>>> def abc(a, b):
...     a, b = b, a
... 
>>> dis.dis(abc)
2           0 LOAD_FAST                1 (b)
3 LOAD_FAST                0 (a)
6 ROT_TWO             
7 STORE_FAST               0 (a)
10 STORE_FAST               1 (b)
13 LOAD_CONST               0 (None)
16 RETURN_VALUE  

在python中,左侧目标列表中的赋值是从左到右完成的。

a,b = b,a 是如何实现的?

首先,b, a创建一个元组。您可以使用例如

>>> tmp = 1, 2
>>> tmp
(1, 2)

然后,赋值使用序列解包,覆盖名称 a、b。

>>> tmp = (a, b)
>>> b, a = tmp

两种操作在速度方面如何比较?

这将取决于你对python的实现。如果您使用 CPython(标准版本(,那么C++可能会快得多,因为它是经过编译和优化的。

CPython 实施细节

在CPython中,交换有时会被优化。对于小交换(<4 个元素(,它使用优化的交换

>>> def swap(a, b):
>>>     a, b = b, a
>>> dis.dis(swap)
3           0 LOAD_FAST                1 (b)
3 LOAD_FAST                0 (a)
6 ROT_TWO
7 STORE_FAST               0 (a)
10 STORE_FAST               1 (b)
13 LOAD_CONST               0 (None)
16 RETURN_VALUE
>>> def swap(a, b, c):
>>>     a, b, c = c, b, a
>>> dis.dis(swap)
3           0 LOAD_FAST                2 (c)
3 LOAD_FAST                1 (b)
6 LOAD_FAST                0 (a)
9 ROT_THREE
10 ROT_TWO
11 STORE_FAST               0 (a)
14 STORE_FAST               1 (b)
17 STORE_FAST               2 (c)
20 LOAD_CONST               0 (None)
23 RETURN_VALUE

对于 4 个或更多元素的交换,它完全按照我上面写的去做,没有优化。

>>> def swap(a, b, c, d):
>>>     a, b, c, d = d, c, b, a
>>> dis.dis(swap)
3           0 LOAD_FAST                3 (d)
3 LOAD_FAST                2 (c)
6 LOAD_FAST                1 (b)
9 LOAD_FAST                0 (a)
12 BUILD_TUPLE              4
15 UNPACK_SEQUENCE          4
18 STORE_FAST               0 (a)
21 STORE_FAST               1 (b)
24 STORE_FAST               2 (c)
27 STORE_FAST               3 (d)
30 LOAD_CONST               0 (None)
33 RETURN_VALUE

补充Sapan的答案:

在C++它可能在概念上使用第三个变量来交换。但是你可以在这里看到,编译器可以生成与python所示相同的程序集:

void foo(int& a, int& b)
{
std::swap(a, b);
}

变成

foo(int&, int&):
mov     eax, DWORD PTR [rdi]
mov     edx, DWORD PTR [rsi]
mov     DWORD PTR [rdi], edx
mov     DWORD PTR [rsi], eax
ret

https://godbolt.org/g/dRrzg6

不完全回答关于 python 的实现,但关于std::swap的重要背景。

C++std::swap不会简单地使用第三个变量交换两个变量。它将使用内部状态的知识来加速它。

std::arraystd::vector的一些示例: https://gcc.godbolt.org/z/MERLGZ

在这两种情况下,它都不会使用第三个变量来复制整个对象,而是直接交换两种类型的内部表示。

array的情况下,我们有分支,用于数组是否正确对齐的情况。 如果是,则将使用两个xmm寄存器交换整个对象,如果不是,它将分别交换每个元素。

vector的情况下,我们在两个对象之间交换内部指针。

std::swap的另一个重要事情是std::move,这是C++11的添加,允许轻松交换两个通常无法像std::unique_ptr那样复制的变量。

现在std::swap的通用版本如下所示:

template<typename Tp>
inline void swap(Tp& a, Tp& b)
{
Tp tmp = std::move(a);
a = std::move(b);
b = std::move(tmp);
}

如果您的类型需要内存分配来应对并且它支持移动,则不会在那里进行内存分配。

可能C++做的大多数事情都不适用于python如何处理其对象。