Что выведет код с изменяемым аргументом по умолчанию

48. Что выведет код с изменяемым аргументом по умолчанию

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

def extendList(val, list=[]):
  list.append(val)
  return list
 
 list1 = extendList(10)
 list2 = extendList(123, [])
 list3 = extendList('a')
 
 print ""list1 = %s"" % list1
 print ""list2 = %s"" % list2
 print ""list3 = %s"" % list3
Спойлеры к решению
Подсказки
  • Аргумент по умолчанию list=[] создаётся один раз в момент определения функции.
  • Если функцию вызвать без второго аргумента, будет использоваться один и тот же список.
  • list1 и list3 используют общий список по умолчанию.
  • list2 использует отдельный список, потому что он передан явно: [].
  • Не стоит называть параметр list, потому что так перекрывается встроенный тип list.
Решение

Исходная идея кода:

def extendList(val, list=[]):
    list.append(val)
    return list


list1 = extendList(10)
list2 = extendList(123, [])
list3 = extendList("a")

print("list1 = %s" % list1)
print("list2 = %s" % list2)
print("list3 = %s" % list3)

Результат:

list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']

Разбор:

list1 = extendList(10)

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

[10]

Дальше:

list2 = extendList(123, [])

Здесь вторым аргументом явно передан новый пустой список. Поэтому 123 добавляется не в общий список по умолчанию, а в отдельный список:

[123]

Дальше:

list3 = extendList("a")

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

[10, "a"]

Так как list1 и list3 ссылаются на один и тот же список, при выводе оба будут равны:

[10, "a"]

Правильная реализация без изменяемого аргумента по умолчанию:

def extend_list(val, items=None):
    if items is None:
        items = []

    items.append(val)
    return items

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