python中的a,b = b,a与C ++中的std :: swap()

时间:2018-08-24 07:20:02

标签: python c++

我知道a,b = b,a基本上是在给元组(a,b)分配另一个元组(b,a)的值。从本质上讲,这是将值从a交换为b,并将值从b交换为a。因此,导致“交换”。

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

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

a,b = b,a的实施方式是什么?

python还会使用第三个临时变量吗?如果没有,它如何运作?

这两种操作在速度方面如何比较?我猜想,如果python也使用第三个变量,则执行时间的差异将归因于python的解释。

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

4 个答案:

答案 0 :(得分:13)

对于元组分配,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中,左侧目标列表中的分配是从左到右完成的。

答案 1 :(得分:8)

  

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

答案 2 :(得分:5)

添加到萨潘的答案:

在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

答案 3 :(得分:4)

关于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处理其对象的方式。