Python - входящий исходящий аргумент - PullRequest
1 голос
/ 09 февраля 2012

Я читал в Expert Python Programming об этом крайнем случае. Проверьте этот код:

def f(arg={}):
    arg['3'] = 4
    return arg

>>> print f()
{'3': 4}
>>> res = f()
>>> res['4'] = 'Still here'
>>> print f()
{'3': 4, '4': 'Still here'}

Мне не понятно, почему, когда f вызывается в последний раз (после того, как его возвращаемое значение было сохранено), вместо присвоения arg пустого dict (так как он был вызван без аргументов), он сохраняет старую ссылку .

В книге говорится так: «если объект создан в пределах аргументов, ссылка на аргумент будет по-прежнему жива, если функция возвращает объект».

Я понимаю, что "это так работает", но почему так?

Ответы [ 3 ]

2 голосов
/ 09 февраля 2012

Поскольку аргументы по умолчанию оцениваются только один раз, когда функция оценивается и создается (они являются частью определения функции и могут быть получены, например, через inspect.getargspec).

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

Та же «особенность» существует в определениях классов, учитывая определение классов:

class A(object):
    foo = {}

вызов

x = A() 
y = A()
x.foo['bar'] = "baz"

... даст y.foo ['bar'] значение "baz", поскольку x и y имеют одинаковое foo.Вот почему инициализация члена должна выполняться в init вместо тела класса.

2 голосов
/ 09 февраля 2012

В вашей задаче по умолчанию используется изменяемый аргумент (в данном случае словарь):

def f(arg={}):
    arg['3'] = 4
    return arg

должно быть:

def f(arg=None):
    arg = arg if arg is not None else {}
    arg['3'] = 4
    return arg

выход:

>>> print f()
{'3': 4}
>>> res = f()
>>> res['4'] = 'Still here'
>>> print f()
{'3': 4}

как и следовало ожидать.

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

Почему, посмотрите "Наименьшее изумление" и изменяемый аргумент по умолчанию

1 голос
/ 09 февраля 2012

Параметр по умолчанию создается один раз, когда объявляется функция, поэтому каждый вызов функции f () получает один и тот же экземпляр словаря, который начинается пустым. Это отвечает на вопрос?

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