Создание функций в цикле

Я пытаюсь создать функции внутри цикла:

functions = []

for i in range(3):
    def f():
        return i

    # alternatively: f = lambda: i

    functions.append(f)

Проблема в том, что все функции в конечном итоге одинаковы. Вместо того, чтобы возвращать 0, 1 и 2, все три функции возвращают 2:

print([f() for f in functions])
# expected output: [0, 1, 2]
# actual output:   [2, 2, 2]

Почему это происходит и что мне делать, чтобы получить 3 разные функции, которые выводят 0, 1 и 2 соответственно?

78
задан Aran-Fey 26 March 2019 в 16:42
поделиться

1 ответ

У вас проблема с поздним связыванием - каждая функция ищет i как можно позже (таким образом, при вызове после окончания цикла, i будет установлено на 2 ) .

Легко исправить путем принудительного раннего связывания: измените def f (): на def f (i = i): вот так:

def f(i=i):
    return i

Значения по умолчанию (справа i в i = i - значение по умолчанию для имени аргумента i , которое является левым i в i. = i ) ищутся во время def , а не во время вызова , так что по сути это способ специально искать раннее связывание.

Если вас беспокоит, что f получит дополнительный аргумент (и, следовательно, потенциально может быть вызван ошибочно), есть более изощренный способ, предполагающий использование замыкания в качестве «фабрики функций»:

def make_f(i):
    def f():
        return i
    return f

и в вашем цикле используйте f = make_f (i) вместо оператора def .

136
ответ дан 24 November 2019 в 10:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: