Разница между написанием чего-то на одной линии и несколькими строками

Где разница, когда я пишу что-то на одной строке, разделенной буквой a и двумя строками. По-видимому, я не понимаю разницы, потому что, хотя две функции ниже должны возвращать то же самое.

 def fibi(n): a, b = 0, 1 for i in range(n): a, b = b, a + b return a print(fibi(6)) > 8 # expected result (Fibonacci) 

Но

 def fibi(n): a, b = 0, 1 for i in range(n): a = b b = a + b return a print(fibi(6)) > 32 

Это происходит из-за распаковки кортежей Python. В первом из них Python собирает значения справа, делает их кортежем, а затем присваивает значениям кортежа индивидуально именам слева. Итак, если a == 1 и b == 2:

  a, b = b, a + b => a, b = (2, 3) => a = 2, b = 3 

Но во втором примере это нормальное назначение:

  a = b => a = 2 b = a + b => b = 4 

Найти замену

 a, b = b, a + b 

вы должны осознавать, что это назначение выполняется «шаг за шагом».

Таким образом, его эквивалент

 old_a = a a = b b = old_a + b # note the old_a here, as a has been replaced in the meanwhile. 

Демо-версия:

 def fibi(n): a, b = 0, 1 for i in range(n): a, b = b, a + b return a def fibi2(n): a, b = 0, 1 for i in range(n): old_a = a a = b b = old_a + b return a >>> fibi(0) 0 >>> fibi(1) 1 >>> fibi(2) 1 >>> fibi(3) 2 >>> fibi(4) 3 >>> fibi(5) 5 >>> fibi(6) 8 >>> fibi(7) 13 >>> >>> >>> >>> fibi2(0) 0 >>> fibi2(1) 1 >>> fibi2(2) 1 >>> fibi2(3) 2 >>> fibi2(4) 3 >>> fibi2(5) 5 >>> fibi2(6) 8 >>> fibi2(7) 

Ваша разница в строках:

1)

 >>> a, b = 0, 1 >>> a, b = b, a+b >>> a 1 >>> b 1 

против:

2)

 >>> a, b = 0, 1 >>> a = b >>> b = a+b >>> a 1 >>> b 2 

в первом случае a = 1 и b = 0 + 1 до изменения значений переменной. Вы в основном говорите «с (a,b) в заданном состоянии X, задайте (a,b) значения (0,1) ».

Хороший способ увидеть разницу в таких вещах – использовать модуль разборки (см. Ссылку, чтобы увидеть смысл кодов):

 >>> from dis import dis >>> a, b = 0, 1 >>> dis('a, b = b, a+b') 1 0 LOAD_NAME 0 (b) 3 LOAD_NAME 1 (a) 6 LOAD_NAME 0 (b) 9 BINARY_ADD 10 ROT_TWO 11 STORE_NAME 1 (a) 14 STORE_NAME 0 (b) 17 LOAD_CONST 0 (None) 20 RETURN_VALUE >>> a, b = 0, 1 >>> dis('a = b; b = a+b') 1 0 LOAD_NAME 0 (b) 3 STORE_NAME 1 (a) 6 LOAD_NAME 1 (a) 9 LOAD_NAME 0 (b) 12 BINARY_ADD 13 STORE_NAME 0 (b) 16 LOAD_CONST 0 (None) 19 RETURN_VALUE 

Разница заключается в том, что во втором примере вы устанавливаете a до b перед ссылкой на a . Ваши значения во втором примере будут отключены. Вот пример:

 a = 5 b = 6 

Ex.1:

 a, b = b, a+b // a = 6 and b = 11 

ex.2:

 a = b // a = 6 b = a + b // b = 6+6 or 12 

Первый пример правильный

Идеальное объяснение Raymond Hettinger можно найти в этом видеоролике PyCon 2013 между 33:13 и 38:17:

https://www.youtube.com/watch?v=OSGv2VnC0go

Цитата из его презентации:

  • не стоит недооценивать преимущества обновления переменных состояния в одно и то же время
  • исключает целый класс ошибок из-за обновлений вне очереди

В первом случае команды

 a, b = b, a + b; 

сначала выполнит сумму a + b а затем выполнит задание. В этом случае b всегда содержит 1. Это объясняет, почему конечный результат равен 6, потому что вы добавляете 1 шесть раз.

Второй код вы разместили правильно.