Skip to content

Latest commit

 

History

History
75 lines (58 loc) · 3.37 KB

File metadata and controls

75 lines (58 loc) · 3.37 KB

Инициализация аргументов по умолчанию

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

function.__defaults__ - атрибут содержит кортеж с аргументами функции по умолчанию.

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

Рассмотрим такой пример кода, тут по умолчанию есть множество, от вызова к вызову это множество меняется, потому что множество изменяемый тип, так что тут надо быть аккуратным.

def unique(iterable, seen=set()):
    acc = []
    for item in iterable:
        if item not in seen:
            seen.add(item)
            acc.append(item)
    return acc

xs = [1, 1, 2, 3]
print(unique(xs))

print('Аргументы по умолчанию', unique.__defaults__)

xs = [1, 1, 2, 3, 4, 5, 6, 7]
print(unique(xs))

print('Аргументы по умолчанию', unique.__defaults__)

# Вывод
# [1, 2, 3]
# Аргументы по умолчанию ({1, 2, 3},)
# [4, 5, 6, 7]
# Аргументы по умолчанию ({1, 2, 3, 4, 5, 6, 7},)

Вывод: стоит избегать в качестве аргументов по умолчанию изменяемые типы данных.

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

def unique(iterable, seen=None):
    acc = []
    seen = set(seen or [])
    
    for item in iterable:
        
        if item not in seen:
            seen.add(item)
            acc.append(item)
            
    return acc

Эта строчка seen = set(seen or []) задает множество, либо то что было передано, либо полностью пустое, то есть None интерпретируется как false мы получаем пустое множество, а если множество было передано то оно и вставляется.