Передача переменного количества аргументов: *args и **kwargs

Зачем нужны args и *kwargs? 🔍

В Python функции часто принимают фиксированное количество аргументов. Но что, если заранее неизвестно, сколько параметров передадут? Вот здесь на сцену выходят *args (arguments) и **kwargs (keyword arguments) — мощные инструменты для работы с переменным числом аргументов!


*args: Передача неименованных аргументов 📦

*args позволяет передавать в функцию произвольное количество позиционных аргументов. Они собираются в кортеж (tuple).

def sum_numbers(*args):
    total = 0
    for num in args:
        total += num
    return total

print(sum_numbers(1, 2, 3))       # 6
print(sum_numbers(10, 20, 30, 40)) # 100

Как это работает? 1. *args "ловит" все переданные позиционные аргументы. 2. Внутри функции args — это обычный кортеж, с которым можно работать.

🔥 Важно: Имя args — это соглашение, но можно использовать любое (например, *numbers). Главное — символ *.


**kwargs: Работа с именованными аргументами 🏷️

Если *args обрабатывает позиционные аргументы, то **kwargs (keyword arguments) работает с именованными аргументами. Они сохраняются в словарь (dict).

def print_user_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_user_info(name="Alice", age=25, country="USA")
# name: Alice
# age: 25
# country: USA

Особенности: - Ключи словаря — это имена аргументов (без кавычек). - Можно комбинировать с обязательными аргументами:

def greet(name, **kwargs):
    print(f"Hello, {name}!")
    if 'city' in kwargs:
        print(f"From {kwargs['city']}?")

Комбинирование args и *kwargs 💥

Эти инструменты можно использовать вместе (и даже с обычными аргументами)! Главное — соблюдать порядок:

def super_function(required_arg, *args, **kwargs):
    print(f"Обязательный аргумент: {required_arg}")
    print(f"*args: {args}")
    print(f"**kwargs: {kwargs}")

super_function("Python", 1, 2, 3, name="Danila", channel="Bezhin")
# Обязательный аргумент: Python
# *args: (1, 2, 3)
# **kwargs: {'name': 'Danila', 'channel': 'Bezhin'}

Правильный порядок параметров:

  1. Обычные аргументы (required_arg).
  2. *args (позиционные).
  3. **kwargs (именованные).

Распаковка аргументов 🎁

* и ** полезны не только для приема, но и для передачи аргументов:

def multiply(a, b):
    return a * b

numbers = (3, 4)
print(multiply(*numbers))  # 12 (распаковка кортежа)

params = {'a': 5, 'b': 6}
print(multiply(**params))  # 30 (распаковка словаря)

Где это применяется? - Передача элементов списка/кортежа как позиционных аргументов. - Передача словаря как именованных аргументов.


Практический пример: Логгер 🛠️

Представим функцию-логгер, которая принимает сообщение и произвольные метаданные:

def log(message, *args, **kwargs):
    print(f"[LOG] {message}")
    if args:
        print("Доп. данные:", args)
    if kwargs:
        print("Метаданные:", kwargs)

log("Запуск системы", 1, 2, 3, user="admin", level="DEBUG")
# [LOG] Запуск системы
# Доп. данные: (1, 2, 3)
# Метаданные: {'user': 'admin', 'level': 'DEBUG'}

Ограничения и подводные камни ⚠️

  1. Порядок аргументов важен: сначала позиционные (*args), потом именованные (**kwargs).
  2. Нельзя использовать несколько *args или **kwargs в одной функции.
  3. Именованные аргументы после *args должны передаваться явно:
def foo(a, *args, b):
    pass

foo(1, 2, 3, b=4)  # b обязательно указать по имени!

Когда это реально полезно? 🎯

  1. Декораторы — чтобы передавать любые аргументы обернутой функции.
  2. Наследование — когда нужно пробросить аргументы в родительский класс.
  3. Функции-обертки — например, для логирования или проверки прав.

Хотите глубже разобрать декораторы? Посмотрите уроки Данилы Бежина на YouTube — там есть отличные примеры!


Закрепляем на практике ✏️

Задача: Напишите функцию format_string, которая: - Принимает строку и произвольное количество именованных аргументов. - Заменяет в строке все {ключи} на соответствующие значения из **kwargs.

def format_string(template, **kwargs):
    for key, value in kwargs.items():
        template = template.replace(f"{{{key}}}", str(value))
    return template

print(format_string("Hello, {name}! Your age is {age}.", name="Danila", age=30))
# Hello, Danila! Your age is 30.

Подсказка: Используйте метод str.replace() и итерацию по kwargs.items().

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

🧠 Учёба без воды и зубрёжки

Закрытый Boosty с наработками опытного преподавателя.

Объясняю сложное так, чтобы щелкнуло.

🚀 Забрать доступ к Boosty