Значения по умолчанию и порядок аргументов

📌 Зачем нужны значения по умолчанию?

Представь ситуацию: ты пишешь функцию для приветствия пользователя. Без значений по умолчанию код выглядел бы так:

def greet(name, greeting):
    print(f"{greeting}, {name}!")

greet("Анна", "Привет")  # Привет, Анна!

Но что, если в 90% случаев мы хотим использовать стандартное приветствие "Привет"? Здесь на помощь приходят значения по умолчанию:

def greet(name, greeting="Привет"):
    print(f"{greeting}, {name}!")

greet("Максим")  # Привет, Максим!
greet("Ольга", "Здравствуйте")  # Здравствуйте, Ольга!

🔥 Суперсила: теперь функция стала гибкой — работает и со стандартным приветствием, и с кастомным!


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

1️⃣ Неизменяемые объекты (числа, строки, кортежи) — идеальные кандидаты:

def create_user(email, role="user", is_active=True):
    print(f"Создан {role} с почтой {email}. Активен: {is_active}")

2️⃣ Изменяемые объекты (списки, словари) — опасно! Используй None:

# ❌ Плохо (один список на все вызовы!)
def add_task(task, tasks=[]):
    tasks.append(task)
    return tasks

# ✅ Правильно
def add_task(task, tasks=None):
    if tasks is None:
        tasks = []
    tasks.append(task)
    return tasks

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


🔀 Порядок аргументов: строгие правила

Python требует соблюдать четкий порядок параметров:

  1. Обычные аргументы (без значений по умолчанию)
  2. Аргументы с дефолтными значениями
  3. *args (если есть)
  4. Только ключевые аргументы
  5. **kwargs (если есть)
# ✅ Правильный порядок
def train_model(data, epochs=10, *, verbose=False, **kwargs):
    pass

# ❌ Ошибка!
def bad_func(a=1, b):  # SyntaxError
    pass

💡 Лайфхак: если порядок сложно запомнить — используй подсказки из IDE (например, PyCharm подсветит ошибку).


🎯 Практика: реальный кейс из веб-разработки

Допустим, мы пишем функцию для API-запроса с типичными параметрами:

def make_api_request(
    endpoint,
    method="GET",
    timeout=5,
    retries=3,
    headers=None,
):
    """Гибкий HTTP-запрос с настройками по умолчанию."""
    if headers is None:
        headers = {"User-Agent": "MyApp/1.0"}

    print(f"Делаем {method} запрос к {endpoint}")
    print(f"Таймаут: {timeout}s, попыток: {retries}")
    print(f"Заголовки: {headers}")

# Использование:
make_api_request("/users")  # Минимальная конфигурация
make_api_request("/posts", "POST", timeout=10)  # Кастомизация

🚀 Фишка: такой подход сочетает удобство для простых случаев и гибкость для сложных.


💡 Продвинутые техники

1. Комбинирование позиционных и именованных аргументов

def connect_db(host, port=5432, user="admin", password=""):
    pass

# Можно смешивать стили:
connect_db("localhost", user="danila", password="qwerty")

2. Аннотации типов с дефолтами

def calculate_tax(
    income: float,
    rate: float = 0.13,
    *,
    verbose: bool = False
) -> float:
    tax = income * rate
    if verbose:
        print(f"Налог: {tax:.2f}")
    return tax

📌 Совет от Данилы Бежина: смотрите его видео про аннотации типов для углубленного изучения.


🧠 Проверь себя

1. Какая ошибка в этом коде?

def process_data(data=[], verbose=True):
    pass

2. Напиши функцию send_email, где:

  • Обязательный параметр: to
  • Необязательные: subject="Без темы", body=""
  • Только ключевые: cc=None, bcc=None

Ответы:

  1. Опасное изменяемое значение по умолчанию data=[]. Нужно заменить на None.
  2. Решение:
def send_email(to, subject="Без темы", body="", *, cc=None, bcc=None):
    pass

Теперь ты мастер аргументов Python! 🎓 Пиши чистый и гибкий код с этими приемами.

Скрыть рекламу навсегда

🎥 YouTube: программирование простым языком

Канал, где я спокойно и по шагам объясняю сложные темы — без заумных терминов и лишней теории.

Подходит, если раньше «не заходило», но хочется наконец понять.

▶️ Смотреть курсы на YouTube