Передача переменного количества аргументов: *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'}
Правильный порядок параметров:
- Обычные аргументы (
required_arg). *args(позиционные).**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'}
Ограничения и подводные камни ⚠️
- Порядок аргументов важен: сначала позиционные (
*args), потом именованные (**kwargs). - Нельзя использовать несколько
*argsили**kwargsв одной функции. - Именованные аргументы после
*argsдолжны передаваться явно:
def foo(a, *args, b):
pass
foo(1, 2, 3, b=4) # b обязательно указать по имени!
Когда это реально полезно? 🎯
- Декораторы — чтобы передавать любые аргументы обернутой функции.
- Наследование — когда нужно пробросить аргументы в родительский класс.
- Функции-обертки — например, для логирования или проверки прав.
Хотите глубже разобрать декораторы? Посмотрите уроки Данилы Бежина на 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().