Python оптимизирует работу с аргументами по умолчанию путем создания их только один раз при определении функции. Это означает, что если аргумент по умолчанию - изменяемый объект (например, список или словарь), он будет общим для всех вызовов функции, если явно не передан новый объект.
Это может привести к неожиданному поведению, если изменяемый аргумент по умолчанию модифицируется внутри функции, так как эти изменения сохранятся для последующих вызовов. Для избежания этого, рекомендуется использовать None
в качестве значения по умолчанию и создавать новый объект внутри функции, если аргумент не был передан.
В Python, работа с аргументами по умолчанию оптимизирована с точки зрения хранения и обработки. Оптимизация заключается в следующем:
1. Значения по умолчанию создаются только один раз: Когда функция определена, значения по умолчанию вычисляются и сохраняются в качестве атрибутов объекта функции. Это происходит только один раз, при определении функции, а не каждый раз, когда она вызывается. Это особенно важно для изменяемых значений (списки, словари и т.д.).
Пример:
def my_function(arg=[]):
arg.append(1)
return arg
print(my_function()) # Вывод: [1]
print(my_function()) # Вывод: [1, 1]
print(my_function()) # Вывод: [1, 1, 1]
В данном примере, если не передать аргумент, будет использован один и тот же список, который изменяется при каждом вызове функции. Это происходит потому что список создается только один раз при определении функции.
2. Ссылка, а не копия: Значение по умолчанию сохраняется как ссылка на объект в памяти. Это означает, что если значение по умолчанию является изменяемым объектом, и он изменяется внутри функции, это изменение сохранится между вызовами функции (как показано в примере выше). Для неизменяемых типов (числа, строки, кортежи) это не имеет значения, так как при их изменении создается новый объект.
3. Оптимизация производительности: Так как значения по умолчанию хранятся как атрибуты функции, Python может получить к ним доступ напрямую, без необходимости пересоздавать их при каждом вызове функции. Это способствует повышению производительности, особенно для сложных или ресурсоемких операций инициализации аргументов.
4. Проверка на наличие аргумента: При вызове функции, Python проверяет, был ли предоставлен аргумент для параметра с значением по умолчанию. Если аргумент предоставлен, он используется. Если нет, используется сохраненное значение по умолчанию.
Важный нюанс: Из-за поведения с изменяемыми значениями по умолчанию, часто рекомендуется использовать None
в качестве значения по умолчанию, а затем создавать новый изменяемый объект внутри функции, если аргумент не был предоставлен.
def my_function(arg=None):
if arg is None:
arg = []
arg.append(1)
return arg
print(my_function()) # Вывод: [1]
print(my_function()) # Вывод: [1]
print(my_function()) # Вывод: [1]
В этом случае, при каждом вызове функции без аргументов, создается новый список.