Подробности о том, как работает a = b = c - PullRequest
0 голосов
/ 15 апреля 2020

Из этого ответа: Как работают цепочечные назначения? , я понимаю, что цепочечное назначение в Python:

x = y = z      # (1)

эквивалентно:

temp = z
x = temp
y = temp

Но (1) также эквивалентно:

x = z
y = x

?

Или есть небольшая разница (например, когда z = some_function())? Если да, то какая разница?

Ответы [ 3 ]

1 голос
/ 15 апреля 2020

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

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

Например, рассмотрим следующее цепочечное выражение, где x инициализируется как dict, а expensive_func - функция, отнимающая много времени который возвращает ключ:

x[expensive_func()] = y = some_function()

Хотя он действительно будет эквивалентен следующему:

temp = some_function()
x[expensive_func()] = temp
y = temp

, он не будет эквивалентен второму подходу:

x[expensive_func()] = some_function()
y = x[expensive_func()]

, поскольку expensive_func необходимо будет вызывать дважды, удваивая затраченное время и дважды вызывая побочный эффект функции, если она есть.

Также рассмотрим следующий код:

obj = []
x = []
x[:] = y = obj
print(id(obj), id(x), id(y))

, где на выходе будет показано, что y назначается та же ссылка, что и obj, тогда как x отличается.

Это тогда код действительно эквивалентен:

obj = []
x = []
temp = obj
x[:] = temp
y = temp
print(id(obj), id(x), id(y))

, но не эквивалентен:

obj = []
x = []
x[:] = obj
y = x[:]
print(id(obj), id(x), id(y))

Последний из которых показывает, что y получает разные ссылки как от obj, так и x.

1 голос
/ 15 апреля 2020

Я всегда считаю, что использование примеров - лучший способ понять вещи (в целом).

Скажем, нам весело c:

def function_sample ():
  print(20)

Если вы напечатаете это :

print(function_sample)

<function function_sample at 0x7f8f840a01f0>

возвращает объект функции.

При присвоении переменной функции без скобок (без вызова / запуска ее).

x = function_sample
print(x)

вы получите то же сообщение: <function function_sample at 0x7f8f840a01f0>

Однако, если вы запустите его (с круглыми скобками).

print(x())

Вы увидите:

20
None

Почему нет? Это потому, что Python функции имеют возвращаемое значение по умолчанию, которое равно None, если выражение возврата не задано, или возвращение дается само по себе.

Другой пример:

def another_sample(some):
  print(some)

y = another_sample
print(y)

Как вы вероятно, догадались : <function another_sample at 0x7f8f7e747700>

Если вы попытаетесь напечатать y (), вы получите ошибку, потому что отсутствует аргумент some.

Но если мы добавим один:

print(y(5))

5
None

Последний пример:

def third_sample ():
  return 20

aa = third_sample    # without running the func
bb = third_sample()  # calling/running the func

print(aa) # function object
print(bb) # 20
0 голосов
/ 15 апреля 2020

2 подхода, которые вы продемонстрировали, являются функциональными и имеют git с точки зрения объединения в цепочку и использования предыдущих переменных. Нет никакой разницы

При присвоении переменных одному и тому же количеству переменных вместо типичного:

x = 0
y = 0

ИЛИ с использованием подхода распаковки кортежей:

(x,y) = 0,0

Вы можете просто сделать то, что у вас есть (цепное назначение):

x = y = 0

Это может быть использовано с любым объектом (вызываемым) для RHS, и это:

x = y = some_object() 

tmp = some_object()
x = tmp
y = tmp

и когда вы del tmp, x и y становятся бесполезными или ничем.

...