Где параметр по умолчанию в функции Python

Я думаю, многие люди видели функцию python, которая получает параметры по умолчанию. Например:

def foo(a=[]):
    a.append(3)
    return a

Если мы будем называть эту функцию с помощью foo(), то после вызова будет добавлено целое число "3".

Когда эта функция определена, объект функции с именем "foo" определяется в текущей среде, а также значения параметров по умолчанию оцениваются в это время. Каждый раз, когда функция вызывается без параметра, значение оцененного параметра будет изменено в соответствии с кодом.

Мой вопрос: , где этот оцениваемый параметр существует? Является ли он в объекте функции или находится в объекте метода при вызове функции? Поскольку все в python является объектом, должно быть место для привязки имени- > значения параметра 'a' → оцененный. Я передумал эту проблему?

Ответ 1

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

Например, в CPython вы можете сделать это:

>>> def f(a=[]):
...     pass
...
>>> f.func_defaults
([],)
>>> f.func_code.co_varnames
('a',)
>>>

Тем не менее, co_varnames может содержать больше имен аргументов, поэтому требуется дальнейшая обработка, и эти атрибуты могут даже отсутствовать в других реализациях Python. Поэтому вместо этого вы должны использовать модуль inspect, который заботится обо всех деталях реализации для вас:

>>> import inspect
>>> spec = inspect.getargspec(f)
>>> spec
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=([],))
>>>

ArgSpec - это именованный кортеж, поэтому вы можете получить доступ ко всем значениям в качестве атрибутов:

>>> spec.args
['a']
>>> spec.defaults
([],)
>>>

Как сообщает документация, кортеж defaults всегда соответствует n последним аргументам из args. Это дает вам ваше отображение.

Чтобы создать dict, вы можете сделать это:

>>> dict(zip(spec.args[-len(spec.defaults):], spec.defaults))
{'a': []}
>>>

Ответ 2

Он привязан к объекту функции, см. foo.func_defaults:

>>> foo()
>>> foo.func_defaults
([3],)
>>> foo()
>>> foo.func_defaults
([3, 3],)

Если вы хотите получить отображение a на [], вы можете получить доступ к foo.func_code:

defaults = foo.func_defaults
# the args are locals in the beginning:
args = foo.func_code.co_varnames[:foo.func_code.co_argcount] 
def_args = args[-len(defaults):]  # the args with defaults are in the end
print dict(zip(def_args, defaults)) # {'a': []}

(Но, по-видимому, версия яков лучше.)

Ответ 3

В объекте функции в func_defaults:

def f(a=[]): a.append(3)

print f.func_defaults # ([],)

f()

print f.func_defaults # ([3],)

Ответ 4

Он сохраняется в атрибуте func_defaults объекта функции.

>>> foo.func_defaults
([],)
>>> foo()
([3],)

Ответ 5

Я нашел интересную ситуацию: в версии python 2.5.2 попробуйте функцию 'foo()'

>>> foo()
[1]
>>> foo()
[1]
>>> foo()
[1]

Поскольку объекты вызываемой функции различаются:

>>> id(foo())
4336826757314657360
>>> id(foo())
4336826757314657008
>>> id(foo())
4336826757314683160

В версии 2.7.2:

>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

В этом случае объект один и тот же каждый раз вызывает функцию:

>>> id(foo())
29250192
>>> id(foo())
29250192
>>> id(foo())
29250192

Это проблема разных версий?