Как правильно задать новую пустую коллекцию в качестве параметра по-умолчанию для функции

Во время решения задачи появилась потребность каждый раз при создании функции обновлять параметр arg дефолтным значением dict()

В процессе решения задачи для меня подобная запись показалась вполне логичной:

def arbitrary(arg = dict()):
    return arg

a = arbitrary()
b = arbitrary()

print(a is b) # True

Однако, как ни странно, при такой записи в arg каждый раз присваивается ссылка на один и тот же словарь.

Далее последовала следующая запись (уже отвечает требованию):

def arbitrary(arg = None):
    if not arg:
        arg = dict()
    return arg

a = arbitrary()
b = arbitrary()

print(a is b) # False

Есть ли какой-нибудь более лаконичный или общепринятый способ записи для этого случая?

UPD: Важное уточнение, пустой словарь должен присваиваться переменной arg на этапе её объявления, либо в самом верху функции. Пример из вопроса - код, ужатый до "воспроизводимой проблемы".


Ответы (2 шт):

Автор решения: denisnumb

Можно так записать:

def arbitrary(arg = None):
    return arg or dict()
→ Ссылка
Автор решения: Amgarak

В Python, параметры по умолчанию вычисляются один раз при определении функции - так что это самый оптимальный вариант:

def arbitrary(arg = dict()):
    return arg or dict()

a = arbitrary()
b = arbitrary()

print(a is b)  # False
print(a, b)    # {} {}

Но если он вам не подходит..

Можно немного поиздеваться над функцией:

def arbitrary(arg = dict()):
    return arg

a = arbitrary()
b = arbitrary()

print(a is b) # True

# Переопределяем параметр по умолчанию перед вызовом функции
a = arbitrary()
arbitrary.__defaults__ = (dict(),)
b = arbitrary()

print(a is b)  # False
print(a, b)    # {} {}

Но в таком случае уже проще декоратор навесить:

def update_default_dict(func):
    def wrapper(*args, **kwargs):
        func.__defaults__ = (dict(),)
        return func(*args, **kwargs)
    return wrapper

@update_default_dict
def arbitrary(arg=dict()):
    return arg

a = arbitrary()
b = arbitrary()

print(a is b)  # False
print(a, b)    # {} {}
→ Ссылка