Значения по умолчанию
Значения по умолчанию
Мы уже умеем передавать аргументы позиционно и по имени. Следующий шаг — сделать некоторые параметры необязательными, задав им значения по умолчанию. Тогда функцию можно вызвать с минимальным набором аргументов, а расширенное поведение использовать лишь когда нужно.
Синтаксис значений по умолчанию
Значение по умолчанию задаётся знаком = прямо в определении функции:
def greet(name, greeting="Привет"):
print(f"{greeting}, {name}!")
greet("Алиса") # Привет, Алиса! — greeting использует default
greet("Борис", "Здравствуй") # Здравствуй, Борис! — default переопределён
greet("Вера", greeting="Добрый день") # именованный аргумент
Параметр с дефолтным значением называют необязательным. При вызове без него Python подставляет значение по умолчанию автоматически.
Правило порядка: обязательные параметры идут первыми
Все параметры без значений по умолчанию должны стоять до параметров со значениями по умолчанию. Иначе Python не сможет понять, к чему относится аргумент:
# OK: сначала обязательные, потом с дефолтом
def connect(host, port=5432, timeout=30):
print(f"Подключение к {host}:{port}, таймаут {timeout}с")
connect("localhost") # host="localhost", port=5432, timeout=30
connect("db.example.com", 3306) # port=3306, timeout=30
connect("db.example.com", timeout=60) # port=5432, timeout=60
# ОШИБКА: обязательный параметр ПОСЛЕ необязательного
# def wrong(port=5432, host): # SyntaxError
# pass
Типичные сценарии применения
Значения по умолчанию особенно полезны там, где большинство вызовов предполагают «стандартный» режим работы:
def log(message, level="INFO", timestamp=True):
prefix = "[INFO]" if level == "INFO" else f"[{level}]"
if timestamp:
import datetime
t = datetime.datetime.now().strftime("%H:%M:%S")
print(f"{t} {prefix} {message}")
else:
print(f"{prefix} {message}")
log("Сервер запущен") # стандартный лог с временем
log("Диск заполнен на 90%", level="WARNING") # предупреждение
log("Тест", timestamp=False) # без временной метки
Функция log() удобна в обоих вариантах: простом и детальном, — без необходимости передавать все параметры каждый раз.
Опасная ловушка: изменяемые значения по умолчанию
Вот одна из самых распространённых ошибок в Python. Никогда не используйте изменяемые объекты ([], {}, set()) в качестве значений по умолчанию:
# ПЛОХО — дефолтный список создаётся ОДИН РАЗ при определении функции:
def append_item(item, lst=[]):
lst.append(item)
return lst
print(append_item(1)) # [1]
print(append_item(2)) # [1, 2] — ожидали [2], но список сохранился!
print(append_item(3)) # [1, 2, 3]
Проблема в том, что значение по умолчанию [] создаётся однажды — при загрузке определения функции. Все вызовы без явного lst используют один и тот же объект списка.
Правильный паттерн — использовать None как часовой:
# ХОРОШО — новый список создаётся при каждом вызове:
def append_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
print(append_item(1)) # [1]
print(append_item(2)) # [2] — теперь каждый раз новый список
Это стандартный Python-идиом. Запомните его: для изменяемых дефолтов — None + проверка внутри функции.
Когда задавать значения по умолчанию
Хорошие кандидаты для дефолтных значений:
- Флаги включения/выключения опции (
verbose=False,dry_run=False) - Типичные настройки (
timeout=30,encoding="utf-8") - Пустые коллекции — только через
None-паттерн - Форматирование по умолчанию (
sep=" ",end="\n"вprint)
Не добавляйте дефолты «на всякий случай». Если параметр всегда должен передаваться явно — оставьте его обязательным. Дефолт уместен, когда для большинства вызовов «стандартное» значение очевидно.
Проверь себя
Что выведет следующий код?
def power(base, exp=2):
return base ** exp
print(power(3))
print(power(3, 3))
print(power(exp=4, base=2))
power(3)→3 ** 2→9power(3, 3)→3 ** 3→27power(exp=4, base=2)→2 ** 4→16
Итог
def f(a, b=10):—bнеобязателен; при вызове без него подставляется10.- Обязательные параметры всегда стоят перед необязательными.
- Никогда не используйте
[]или{}как дефолт — используйтеNoneи создавайте внутри функции. - Дефолты — это контракт: «если не сказали иначе, работаем вот так».
В следующем уроке изучим *args и **kwargs — механизм для функций с переменным числом аргументов.