Ответ 1
Способ, которым работает этот механизм, представляет собой комбинацию двух функций - формирования неявных кортежей и распаковки кортежей/списка.
Когда вы выполните something = x, y
, то, что будет делать Python, неявно создаст 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.)