Задать вопрос
@Tiasar
Web Developer

Почему словарь внутри функции ведет себя как глобальная переменная?

Подскажите новичку, почему такое происходит?
Допустим есть функция:
def testing(myswitch, mydict={}):
    if myswitch:
        mydict.update({'TEST-1': 'qwerty'})
    else:
        mydict.update({'TEST-2': 'qwerty'})
    print(str(mydict))

Если вызвать ее 2 раза подряд так:
testing(True)
testing(False)

То получим результат:

{'TEST-1': 'qwerty'}
{'TEST-1': 'qwerty', 'TEST-2': 'qwerty'}


Я ожидал такой результат:

{'TEST-1': 'qwerty'}
{ 'TEST-2': 'qwerty'}
  • Вопрос задан
  • 247 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 1
sergey-gornostaev
@sergey-gornostaev Куратор тега Python
Седой и строгий
Марк Лутц - "Изучаем Python", глава 17 «Области видимости и вложенные функции» и раздел «Типичные ошибки при работе с функциями» в конце.

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

Например, следующая функция использует пустой список в качестве
значения по умолчанию своего аргумента, а затем изменяет его при
каждом вызове:

>>> def saver(x=[]): # Объект списка сохраняется
    ...     x.append(1)  # При каждом вызове изменяется один и тот же объект!
    ...     print(x)
    ...
    >>> saver([2]) # Значение по умолчанию не используется
    [2, 1]
    >>> saver()    # Используется значение по умолчанию
    [1]
    >>> saver()    # Список растет при каждом вызове!
    [1, 1]
    >>> saver()
    [1, 1, 1]


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

>>> def saver(x=None):
    ...     if x is None: # Аргумент отсутствует?
    ...         x = []    # Создать новый список
    ...     x.append(1)   # Изменить объект списка
    ...     print(x)
    ...
    >>> saver([2])
    [2, 1]
    >>> saver() # Список больше не растет
    [1]
    >>> saver()
    [1]
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы