x,y=y,x在Python中交换值的逻辑是什么?

2024-04-26 22:10:47 发布

您现在位置:Python中文网/ 问答频道 /正文

代码:

x="salil"
y="Ajay"
y,x=x,y

print x +" "+ y

输出:

Ajay salil

对此有什么合理的解释?


Tags: 代码printsalilajay
3条回答

这种机制的工作方式是两个特性的组合——形成隐式元组和元组/列表解包。

当您执行something = x, y操作时,Python将隐式地创建由x和y两个元素组成的tuple(一种不可变列表)。因此,以下两行代码完全等效:

something = x, y
something = (x, y)

当然,元组可以包含两个以上的元素:

something = a, b, c, d, e
something = (a, b, c, d, e)

此功能的预期用例是为了使从函数返回多个值这样的操作更容易/更清晰:

def foo():
    return "hello", "world"

第二个特性是tuple/list解包。每当左边有一系列变量,而另一边有任何类型的列表、元组或其他集合时,Python都会尝试将右边的每个元素与左边的元素匹配起来:

>>> a, b, c = [11, 22, 33]
>>> print(a)
11
>>> print(b)
22
>>> print(c)
33

如果有帮助,那么a, b, c = [11, 22, 33]行与执行以下操作基本相同:

temp = [11, 22, 33]
a = temp[0]
b = temp[1]
c = temp[2]

注意,右边可以是任何类型的集合,而不仅仅是元组或列表。所以下面的代码是有效的:

>>> p, q = "az"
>>> print(p + "  " + q)
a  z
>>>
>>> s, t = {'cat': 'foo', 'dog': 'bar'}
>>> print(s + "  " + t)
cat  dog

(尽管如此,由于Python中的词典没有义务按照任何特定的顺序排列,而且由于密钥的顺序可以自由地进行置乱,因此解包它们可能不会有用,因为每次都可能得到不同的结果。)

如果集合中的变量数和元素数不匹配,Python将抛出异常:

>>> a, b = (1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)

>>> a, b, c = (1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: need more than 2 values to unpack

这意味着如果我们从上面调用foo函数并执行以下操作:

>>> x, y = foo()

…变量x等于字符串"hello",变量y等于字符串"world"


所以最终,这意味着你最初的代码片段:

x = "salil"
y = "Ajay"
y, x = x, y

…在逻辑上等同于:

x = "salil"
y = "Ajay"
temp = (x, y)  # evaluates to ("salil", "Ajay")
y, x = temp

……在逻辑上更是等同于:

x = "salil"
y = "Ajay"
temp = (x, y)  # evaluates to ("salil", "Ajay")
y = temp[0]
x = temp[1]

请注意,您可以认为这两个操作是分别进行的。首先形成元组并对其求值,然后将元组解压回变量中。最终的效果是两个变量的值是互换的。

(然而,事实证明,CPython解释器(Python的原始和“标准”实现)在这里做了一些优化:它将优化交换,而不会进行完整的元组解包——见下面的注释)。我不确定其他Python实现是否也会这样做,尽管我怀疑它们可能会这样做。在任何情况下,这种优化都是特定于实现的,并且独立于Python语言本身的设计。)

这适用于交换,因为首先计算=的右侧。

所以在右边,它评估为

'salil', 'Ajay'

然后xy的赋值发生

 x, y = 'salil', 'Ajay'

好吧,让我们看看:

import dis
src = '''
x="salil"
y="Ajay"
y,x=x,y

print x +" "+ y
'''
code = compile(src, '<string>', 'exec')
dis.dis(code)

这会产生:

  2           0 LOAD_CONST               0 ('salil')
              3 STORE_NAME               0 (x)

  3           6 LOAD_CONST               1 ('Ajay')
              9 STORE_NAME               1 (y)

  4          12 LOAD_NAME                0 (x)
             15 LOAD_NAME                1 (y)
             18 ROT_TWO             
             19 STORE_NAME               1 (y)
             22 STORE_NAME               0 (x)

  6          25 LOAD_NAME                0 (x)
             28 LOAD_CONST               2 (' ')
             31 BINARY_ADD          
             32 LOAD_NAME                1 (y)
             35 BINARY_ADD          
             36 PRINT_ITEM          
             37 PRINT_NEWLINE       
             38 LOAD_CONST               3 (None)
             41 RETURN_VALUE        

请记住,Python是作为堆栈机运行的。在这种情况下,它优化了对ROT_TWO(即swap)指令的赋值。还有一个ROT_THREE指令。但让我们试试别的:

import dis
src = 'x, y, z, w = a, b, c, d'
code = compile(src, '<string>', 'exec')
dis.dis(code)

这产生了一般形式:

  1           0 LOAD_NAME                0 (a)
              3 LOAD_NAME                1 (b)
              6 LOAD_NAME                2 (c)
              9 LOAD_NAME                3 (d)
             12 BUILD_TUPLE              4
             15 UNPACK_SEQUENCE          4
             18 STORE_NAME               4 (x)
             21 STORE_NAME               5 (y)
             24 STORE_NAME               6 (z)
             27 STORE_NAME               7 (w)
             30 LOAD_CONST               0 (None)
             33 RETURN_VALUE        

相关问题 更多 >