Множественное назначение и порядок оценки в Python

В чем разница между следующими выражениями Python:

# First:

x,y = y,x+y

# Second:

x = y
y = x+y

Первый дает другие результаты, чем Второй.

e.g.,

Первый:

>>> x = 1
>>> y = 2
>>> x,y = y,x+y
>>> x
2
>>> y
3

Второе:

>>> x = 1
>>> y = 2
>>> x = y
>>> y = x+y
>>> x
2
>>> y
4

y равно 3 в первом и 4 в втором


person Rafael Carrillo    schedule 04.01.2012    source источник


Ответы (11)


В операторе присваивания правая часть всегда полностью вычисляется перед фактической установкой переменных. Так,

x, y = y, x + y

оценивает y (назовем результат ham), оценивает x + y (назовем его spam), затем устанавливает x в ham и y в spam. то есть это как

ham = y
spam = x + y
x = ham
y = spam

Напротив,

x = y
y = x + y

устанавливает x в y, затем устанавливает y в x (которое == y) плюс y, так что это эквивалентно

x = y
y = y + y
person Fred Foo    schedule 04.01.2012
comment
Чтобы относиться к подобному синтаксису, можно найти в кодовой базе, что x,y = y,x+y идентично (x,y) = y,x+y, поэтому круглые скобки не нужны. Это звучит правильно? - person jxramos; 18.09.2018
comment
@jxramos Да, скобки не нужны, но это больше вопрос о кортежах. - person wjandrea; 13.06.2020

Это объясняется в документации в разделе "Порядок оценки":

... при оценке задания правая часть оценивается раньше левой.

person unutbu    schedule 04.01.2012

Первое выражение:

  1. Создает временный кортеж со значением y,x+y
  2. Назначен другому временному кортежу
  3. Извлеките кортеж в переменные x и y

Второй оператор фактически представляет собой два выражения без использования кортежа.

Сюрприз в том, что первое выражение на самом деле:

temp=x
x=y
y=temp+y

Вы можете узнать больше об использовании запятой в "формах в скобках".

person Abhijit    schedule 04.01.2012

Недавно я начал использовать Python, и эта «функция» меня сбила с толку. Хотя было дано много ответов, я все равно опубликую свое понимание.

Если я хочу поменять местами значения двух переменных в JavaScipt, я бы сделал следующее:

var a = 0;
var b = 1;

var temp = a;
a = b;
b = temp;

Мне понадобится третья переменная для временного хранения одного из значений. Очень простой обмен не сработает, потому что обе переменные получат одно и то же значение.

var a = 0;
var b = 1;

a = b; // b = 1 => a = 1
b = a; // a = 1 => b = 1

Представьте, что у вас есть два разных (красное и синее) ведра и две разные жидкости (вода и масло) в них соответственно. Теперь попробуйте поменять местами ведра/жидкости (вода в синем и масло в красном ведре). Вы не сможете сделать это, если у вас нет дополнительного ведра.

Python справляется с этим более "чистым" способом/решением: Tuple Assignment.

a = 0
b = 1

print(a, b) # 0 1

# temp = a
# a = b
# b = temp

a, b = b, a # values are swapped

print(a, b) # 1 0

Думаю, таким образом Python автоматически создает временные переменные, и нам не нужно о них беспокоиться.

person akinuri    schedule 13.02.2018
comment
Как упоминается в ссылке, все выражения с правой стороны оцениваются перед любым из назначений. Спасибо за эту ясность. - person Harsh Goyal; 31.07.2019

Замечание относительно левой части: порядок присваиваний гарантированно совпадает с порядком их появления, другими словами:

a, b = c, d

функционально эквивалентен точно (кроме создания):

t = (c, d)
a = t[0] # done before 'b' assignment
b = t[1] # done after 'a' assignment

Это имеет значение в таких случаях, как присвоение атрибутов объекта, например:

class dummy:
    def __init__(self): self.x = 0

a = dummy(); a_save = a
a.x, a = 5, dummy()
print(a_save.x, a.x) # prints "5 0" because above is equivalent to "a = dummy(); a_save = a; t = (5, dummy()); a.x = t[0]; a = t[1]"

a = dummy(); a_save = a
a, a.x = dummy(), 5
print(a_save.x, a.x) # prints "0 5" because above is equivalent to "a = dummy(); a_save = a; t = (dummy(), 5); a = t[0]; a.x = t[1]"

Это также означает, что вы можете делать такие вещи, как создание объектов и доступ к ним, используя однострочники, например:

class dummy:
    def __init__(self): self.x = 0
# Create a = dummy() and assign 5 to a.x
a, a.x = dummy(), 5
person Zuzu Corneliu    schedule 22.06.2020

Во втором случае вы назначаете x+y на x

В первом случае второй результат (x+y) присваивается y

Вот почему вы получаете разные результаты.

После редактирования

Это происходит потому, что в заявлении

x,y = y,x+y

все переменные в правом элементе вычисляются и затем сохраняются в левых элементах. Итак, сначала переходите к правому члену, а во-вторых к левому.

Во втором заявлении

x = y
y = x + y

вы сначала оценили y и присвоили его x; таким образом, сумма x+y эквивалентна сумме y+y, а не x+x, что является первым случаем.

person DonCallisto    schedule 04.01.2012

Первый представляет собой присваивание в виде кортежа:

x,y = y,x+y

Где x — первый элемент кортежа, а y — второй элемент, поэтому вы делаете следующее:

x = y
y = x+y

В то время как второй выполняет прямое назначение:

x=y
x=x+y
person Serdalis    schedule 04.01.2012

Другие ответы уже объяснили, как это работает, но я хочу добавить действительно конкретный пример.

x = 1
y = 2
x, y = y, x+y

В последней строке сначала имена разыменовываются следующим образом:

x, y = 2, 1+2

Затем оценивается выражение:

x, y = 2, 3

Затем кортежи расширяются, и затем происходит присваивание, эквивалентное следующему:

x = 2; y = 3
person wjandrea    schedule 13.06.2020

Для новичков я наткнулся на этот пример, который может помочь объяснить это:

# Fibonacci series:
# the sum of two elements defines the next
a, b = 0, 1
while a < 10:
    print(a)
    a, b = b, a+b

При множественном присвоении установите начальные значения как a=0, b=1. В цикле while обоим элементам присваиваются новые значения (отсюда и название «множественное» присваивание). Просмотрите это как (a,b) = (b,a+b). Итак, a = b, b = a+b на каждой итерации цикла. Это продолжается, пока a‹10.

РЕЗУЛЬТАТЫ: 0 1 1 2 3 5 8

person Angela C    schedule 24.11.2020

Давайте почувствуем разницу.

x, y = y, x + y Это x кортеж xssignment, mexns (x, y) = (y, x + y), как и (x, y) = (y, x)

Быстрый пример Stxrt из x:

x, y = 0, 1
#equivxlent to
(x, y) = (0, 1)
#implement xs
x = 0
y = 1

Когда дело доходит до (x, y) = (y, x + y) ExFP, попросите x попробовать напрямую

x, y = 0, 1
x = y #x=y=1
y = x + y #y=1+1
#output
In [87]: x
Out[87]: 1
In [88]: y
Out[88]: 2

Однако,

In [93]: x, y = y, x+y
In [94]: x
Out[94]: 3
In [95]: y
Out[95]: 5

Результат отличается от первой попытки.

Спасибо, потому что Python сначала оценивает правую x+y Так что это эквивалентно:

old_x = x
old_y = y
c = old_x + old_y
x = old_y
y = c

Таким образом, x, y = y, x+y означает, что
x обменивается, чтобы получить old_value из y,
y обменивается, чтобы получить сумму старого значения x и старого значения y,

person AbstProcDo    schedule 17.01.2018

a, b = 0, 1
while b < 10:
    print(b)
    a, b = b, a+b

Выход

1
1
2
3
5
8

переменные a и b одновременно получают новые значения 0 и 1, те же самые a, b = b, a+b, a и b присваиваются одновременно.

person li bing zhao    schedule 19.09.2017