Параметр python по умолчанию оценивается только один раз?

Я начинаю питон, читая «учебник по python», он говорит, что если у нас есть функция:

def f(a, L=[]): L.append(a) return L print f(1) print f(2) print f(3) 

Это напечатает

 [1] [1, 2] [1, 2, 3] 

Поскольку значение по умолчанию оценивается только один раз, а list – изменяемый объект. Я могу это понять.

И он говорит, что продолжайте, если мы не хотим, чтобы по умолчанию были доступны общие вызовы, мы можем:

 def f(a, L=None): if L is None: #line 2 L = [] L.append(a) return L print f(1) print f(2) print f(3) 

и это будет выводить:

 [1] [2] [3] 

Но почему ? Как это объяснить. Мы знаем, что значение по умолчанию оценивается только once , и когда мы вызываем f (2), L не является None и что if (в строке 2) не может быть истинным, то L.append (a) == [1, 2]. Мог ли я предположить, что значение по умолчанию снова оценивается по какой-то причине , но что такое «какая-то причина», просто потому, что интерпретатор python видит, if L is None: L = []

5 Solutions collect form web for “Параметр python по умолчанию оценивается только один раз?”

«Значение по умолчанию оценивается только один раз» не означает, что параметр со значением по умолчанию сохраняет свое значение между вызовами функции. Это означает, что указанное вами выражение (часть None из def f(a, L=None) ) оценивается один раз, а объект, который он приводит, хранится в скрытом местоположении и повторно используется, если значение для этого параметра не равно данный при вызове. Параметры по-прежнему сбрасываются до значения (по умолчанию или нет) при каждом вызове.

Python передает параметры функциям по значению; Таким образом, для объектов переданное значение является ссылкой на объект , а не новой копией объекта.

Это, наряду со следующей частью официальных документов, помогло мне лучше понять (внимание мое):

Значения параметров по умолчанию оцениваются […], когда выполняется определение функции. Это означает, что выражение оценивается один раз, когда функция определена, и что для каждого вызова используется одно и то же «предварительно вычисленное» значение. Это особенно важно для понимания, когда параметр по умолчанию является изменяемым объектом, таким как список или словарь: если функция изменяет объект (например, добавив элемент в список), значение по умолчанию изменяется. […] Путь к этому – использовать None в качестве значения по умолчанию и явно проверить его в теле функции […]

Объединяя все это:

Если вы определяете параметр по умолчанию для изменяемого объекта (например, [] ), то «предварительно вычисленное» значение является ссылкой на этот объект, поэтому каждый вызов функции всегда ссылается на тот же объект, который затем может быть мутированным по нескольким вызовам функции.

Однако, поскольку None является неизменным встроенным типом, «предварительно вычисленное» значение для значения по умолчанию « None просто так. Таким образом, каждый раз, когда вы вызываете эту функцию, параметр будет None .

Надеюсь, это поможет! Я действительно думаю, что учебник мог иметь лучшую формулировку, потому что сначала меня это смутило.

Во втором примере у вас есть переменная L Сначала L относится к None . Вы отправляете его в новый пустой список для каждого вызова, а затем мутируете этот новый список. Помните, что L = [] совпадает с L = list()

Однако в вашем первом примере L устанавливается в новый список один раз в объявлении функции. L не сбрасывается на [] при каждом вызове функции. Таким образом, вы всегда мутируете один и тот же список.

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

Для первой функции переменная L находится вне среды функций (в определении функции), и она относится к пустым спискам. Затем вы вносите изменения в этот список в среду функций, но поскольку список изменен, переменная L, которая находится за пределами функциональной среды, ссылается на этот теперь мутированный список, и это изменение распространяется при каждом вызове функции.

Для второй функции переменная L также находится вне среды функций (в определении функции), но на этот раз она ссылается на None, что является неизменным. Теперь каждое изменение, которое вы выполняете в функциональной среде, не повлияет на то, что L означает вне среды функций. Переменная L внутри функциональной среды относится к чему-то другому по мере ее изменения. Во-первых, это относится к пустым спискам, а затем к списку, который получает добавленное к нему значение. Затем вы возвращаете этот список. При следующем вызове функции вы вызываете ее с переменной L, которая находится вне среды функций, которая не изменилась и по-прежнему относится к None.

Надеюсь, это имеет смысл.

Что происходит, так это:

Когда вызывается функция python, она оценивается в среде, в которой она была определена, а не в среде, в которой она была вызвана, хотя вторая часть является вторичной (каламбур не предназначен) для ответа на ваш вопрос.

Аргументы по умолчанию оцениваются только один раз во время определения функции. Это создает закрытие. Подумайте о закрытии как функциональный код + среда, в которой была определена функция.

Таким образом, в этом случае, когда функция была определена, L был назначен [] и теперь каждый последующий вызов функции будет использовать это значение L

В учебнике также упоминается:

Значения по умолчанию оцениваются в точке определения функции в определяющей области (и определяющая область является частью замыкания вместе с кодом функции)

http://docs.python.org/2/tutorial/controlflow.html#default-argument-values

Python - лучший язык программирования в мире.