Коротко
*args собирает позиционные аргументы в кортеж, **kwargs — именованные в словарь. Удобно для обёрток, декораторов и гибких API.
def log(level, *args, **kwargs):
print(level, args, kwargs)
log("INFO", "start", user="ann")
# INFO ('start',) {'user': 'ann'}
Распаковка при вызове:
def add(a, b):
return a + b
pair = (1, 2)
add(*pair)
Порядок параметров
обычные, затем *args, затем keyword-only, затем **kwargs.
Короткий ответ
«*args — лишние позиционные в tuple, **kwargs — лишние именованные в dict. Нужны для гибких функций и проксирования аргументов.»