вопрос об именах питона, использующих значение параметра по умолчанию - PullRequest
2 голосов
/ 12 августа 2010

Я читал это сегодня: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#default-parameter-values, и я не могу понять, что происходит под капотом.

def bad_append(new_item, a_list=[]):
    a_list.append(new_item)
    return a_list

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

Прежде всего, я думаю, когда начинается этап определения функции?Является ли это этапом инициализации непосредственно перед выполнением фактической главной функции?

Я изначально думал, что имя a_list удаляется сразу после запуска функции, поэтому все, что мутирует [], будет собираться мусором.Теперь я думаю, что a_list вообще не отбрасывается, поскольку это только имя, связанное с объектом [], поэтому он никогда не получает мусор, потому что a_list все еще привязан к нему.Но опять же, мне интересно, как я получаю то же значение по умолчанию вместо нового [].Может кто-нибудь исправить это для меня?

Спасибо!

1 Ответ

2 голосов
/ 12 августа 2010

когда стадия определения функции?

Посмотрите на "Определения функций" в справочнике по Python:

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

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

Параметры оцениваются при выполнении определения функции . Если это в модуле, это происходит, когда модуль импортируется. Если это в классе, это когда определение класса выполняется. Если это в функции, это происходит, когда функция выполняется. Помните, что модуль Python оценивается сверху вниз и автоматически не имеет явной «основной функции», как некоторые языки.

Например, если вы поместите определение функции внутри функции, вы будете получать новую копию функции каждый раз:

>>> def make_function():
...     def f(value=[]):
...             value.append('hello')
...             return value
...     return f
... 
>>> f1 = make_function()
>>> f2 = make_function()
>>> f1()
['hello']
>>> f1()
['hello', 'hello']
>>> f2()
['hello']

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

Первоначально я думал, что имя a_list удаляется сразу после запуска функции, поэтому все, что мутирует [], будет собирать мусор.

Внутри тела функции для кода доступно имя a_list. Таким образом, имя и значение, на которое оно указывает, оба должны быть доступны. Он сохраняется в атрибуте func_defaults функции.

Но опять же, мне интересно, как я получаю то же значение по умолчанию вместо нового [].

Поскольку [] оценивается только тогда, когда определена функция, а не когда она вызывается, а имя a_list указывает на один и тот же объект даже при повторных вызовах. Опять же, если вам нужно альтернативное поведение, используйте что-то неизменное, например None, и проверьте его.

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