Аргументы по умолчанию получают оценку во время компиляции функции в объект функции. При использовании этой функции, несколько раз с помощью этой функции, они являются и остаются одним и тем же объектом.
Когда они изменяются, когда они мутируются (например, добавляя к нему элемент), они остаются мутированными по последовательным вызовам.
Они остаются мутированными, потому что каждый раз они являются одним и тем же объектом .
Поскольку список связан с функцией, когда объект функции компилируется и инстанцируется, это:
def foo(mutable_default_argument=[]): # make a list the default argument
"""function that uses a list"""
почти точно эквивалентно этому:
_a_list = [] # create a list in the globals
def foo(mutable_default_argument=_a_list): # make it the default argument
"""function that uses a list"""
del _a_list # remove globals name binding
Вот демонстрация - вы можете проверить, что они являются одним и тем же объектом каждый раз, когда они ссылаются на
example.py
print('1. Global scope being evaluated')
def create_list():
'''noisily create a list for usage as a kwarg'''
l = []
print('3. list being created and returned, id: ' + str(id(l)))
return l
print('2. example_function about to be compiled to an object')
def example_function(default_kwarg1=create_list()):
print('appending "a" in default default_kwarg1')
default_kwarg1.append("a")
print('list with id: ' + str(id(default_kwarg1)) +
' - is now: ' + repr(default_kwarg1))
print('4. example_function compiled: ' + repr(example_function))
if __name__ == '__main__':
print('5. calling example_function twice!:')
example_function()
example_function()
и работает это с python example.py
:
1. Global scope being evaluated
2. example_function about to be compiled to an object
3. list being created and returned, id: 140502758808032
4. example_function compiled:
5. calling example_function twice!:
appending "a" in default default_kwarg1
list with id: 140502758808032 - is now: ['a']
appending "a" in default default_kwarg1
list with id: 140502758808032 - is now: ['a', 'a']
Этот порядок выполнения часто путает новых пользователей Python. Если вы понимаете модель исполнения Python, это становится вполне ожидаемым.
Но поэтому обычная инструкция для новых пользователей заключается в том, чтобы вместо этого создать свои аргументы по умолчанию:
def example_function_2(default_kwarg=None):
if default_kwarg is None:
default_kwarg = []
Это использует None singleton как объект-дозор, чтобы сообщить функции, есть ли у нас аргумент, отличный от значения по умолчанию. Если мы не получаем никакого аргумента, то мы действительно хотим использовать новый пустой список []
в качестве значения по умолчанию.
Как говорится в разделе в разделе управления потоком :
Если вы не хотите, чтобы по умолчанию были разделены между последующими вызовами, вы можете написать такую функцию, как это:
def f(a, L=None): if L is None: L = [] L.append(a) return L