Почему default-аргумент не перезаписывается?
Скажите пожалуйста, почему в следующем коде на третьем вызове функции f() значение l становится [0, 1]
def f(x, l=[]):
print('=====', l)
for i in range(x):
l.append(i*i)
print(l)
f(2)
f(3, [3, 2, 1])
f(3)
Вывод:
===== []
[0, 1]
===== [3, 2, 1]
[3, 2, 1, 0, 1, 4]
===== [0, 1]
[0, 1, 0, 1, 4]
Есть ли этому логическое объяснение? Это можно запомнить, но хотелось бы именно понять.
Ход моей мысли такой:
- функция f() при первом вызове заполняет l значением [0, 1]
- при втором вызове функции f() значение l перезаписывается. То есть предыдущее значение удаляется
- теоретически при третьем вызове в l должно содержаться или [] или [3, 2, 1, 0, 1, 4]
- НО там содержится [0, 1]. ОТКУДА?..
Ответы (1 шт):
при втором вызове функции f() значение l перезаписывается. То есть предыдущее значение удаляется
Нет. Как раз в этом Вы и заблуждаетесь. Значение l остаётся прежним, а функция использует переданное значение.
НО там содержится [0, 1]. ОТКУДА?..
Изменённое стандартное значение l после первого вызова функции.
Чтобы подтвердить мною сказанное, давайте дизассемблируем код (последние 2 вызова):
10 20 LOAD_NAME 0 (f)
22 LOAD_CONST 3 (3)
24 LOAD_CONST 3 (3)
26 LOAD_CONST 2 (2)
28 LOAD_CONST 4 (1)
30 BUILD_LIST 3
32 CALL_FUNCTION 2
34 POP_TOP
11 36 LOAD_NAME 0 (f)
38 LOAD_CONST 3 (3)
40 CALL_FUNCTION 1
42 POP_TOP
Обратите внимание на инструкцию CALL_FUNCTION. Её описание:
CALL_FUNCTION(argc)
Вызывает вызываемый объект с позиционными аргументами. argc указывает количество позиционных аргументов.
Когда Вы вызывали функцию, заменяя стандартный аргумент, происходило следующее:
32 CALL_FUNCTION 2
# ^^^
Python для вызова брал 2 аргумента из стека. l вообще не участвует при вызове и тем более не перезаписывается.
Когда Вы не передавали второй аргумент, Python брал его из объекта функции (брал l):
40 CALL_FUNCTION 1
# ^^^