Как работают цепные задания? - PullRequest
27 голосов
/ 29 сентября 2011

Цитата из чего-то:

>>> x = y = somefunction()

совпадает с

>>> y = somefunction()
>>> x = y

Вопрос:

x = y = somefunction()

так же, как

x = somefunction()
y = somefunction()

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

Ответы [ 5 ]

43 голосов
/ 01 апреля 2016

Ни то, ни другое.

x = y = some_function()

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

temp = some_function()
x = temp
y = temp

Обратите внимание на заказ. Самая левая цель назначается первой .(Аналогичное выражение в C может назначаться в в обратном порядке .) Из документов по Python назначение :

...assigning один результирующий объект для каждого из списков целей, слева направо.

Разборка показывает это:

>>> def chained_assignment():
...     x = y = some_function()
...
>>> import dis
>>> dis.dis(chained_assignment)
  2           0 LOAD_GLOBAL              0 (some_function)
              3 CALL_FUNCTION            0
              6 DUP_TOP
              7 STORE_FAST               0 (x)
             10 STORE_FAST               1 (y)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE

ВНИМАНИЕ: то же самоеобъект всегда присваивается каждой цели.Итак, как указывают @Wilduck и @andronikus, вы, вероятно, никогда не захотите этого:

x = y = []   # Wrong.

В приведенном выше случае x и y относятся к одному и тому же списку.Поскольку списки изменяемые , добавление к x может повлиять на y.

x = []   # Right.
y = []

Теперь у вас есть два имени, относящихся к двум разным пустым спискам.

35 голосов
/ 29 сентября 2011

Они не обязательно будут работать одинаково, если somefunction возвращает изменяемое значение.Рассмотрим:

>>> def somefunction():
...     return []
... 
>>> x = y = somefunction()
>>> x.append(4)
>>> x
[4]
>>> y
[4]
>>> x = somefunction(); y = somefunction()
>>> x.append(3)
>>> x
[3]
>>> y
[]
13 голосов
/ 29 сентября 2011

Что если somefunction() возвращает разные значения при каждом вызове?

import random

x = random.random()
y = random.random()
4 голосов
/ 14 июня 2016

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

Например:

def is_computer_on():
    return True

x = y = is_computer_on()

или

def get_that_constant():
    return some_immutable_global_constant

Обратите внимание, что результат будет таким же, но процесс для достижения результата не будет:

def slow_is_computer_on():
    sleep(10)
    return True

Содержимое переменных x и yбудет такой же, но инструкция x = y = slow_is_computer_on() будет длиться 10 секунд, а ее аналог x = slow_is_computer_on() ; y = slow_is_computer_on() будет длиться 20 секунд.

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

Например:

def count_three(i):
    return (i+1, i+2, i+3)

x = y = count_three(42)

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

Почему я говорю почти ?Из-за этого:

x = y = count_three(42)
x is y  # <- is True

x = count_three(42)
y = count_three(42)
x is y  # <- is False

Хорошо, использование is является чем-то странным, но это показывает, что результат не тот.Это важно для изменчивого случая:

Это опасно и может привести к ошибкам, если функция возвращает изменяемый

На этот вопрос также был дан ответ в этом вопросе.Для полноты картины я повторю аргумент:

def mutable_count_three(i):
    return [i+1, i+2, i+3]

x = y = mutable_count_three(i)

Поскольку в этом сценарии x и y являются одним и тем же объектом, выполнение операции, подобной x.append(42), означало бы, что оба xи y содержит ссылку на список, который теперь имеет 4 элемента.

Это не будет то же самое, если функция имеет побочные эффекты

С учетом побочного эффекта печати (которыйЯ нахожу действительным, но вместо этого можно использовать другие примеры):

def is_computer_on_with_side_effect():
    print "Hello world, I have been called!"
    return True

x = y = is_computer_on_with_side_effect()  # One print

# The following are *two* prints:
x = is_computer_on_with_side_effect()
y = is_computer_on_with_side_effect()

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

Это не было бы то же самое, если бы функция была недетерминированной, учитывая ее входные данные

Возможно простой случайный метод:

def throw_dice():
    # This is a 2d6 throw:
    return random.randint(1,6) + random.randint(1,6)

x = y = throw_dice()  # x and y will have the same value

# The following may lead to different values:
x = throw_dice()
y = throw_dice()

Но все, что связано с часами, глобальными счетчиками, системными компонентами и т. Д., Имеет смысл быть недетерминированным, учитывая входные данные, и в этих случаях значения x и y могут отличаться.

4 голосов
/ 16 марта 2014

In

x = somefunction()
y = somefunction()

somefunction будет вызываться дважды, а не один раз.

Даже если он возвращает один и тот же результат каждый раз, это будет заметно, если это займет минутувернуть результат!Или, если он имеет побочный эффект, например, спрашивая у пользователя его пароль.

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