Переменное количество аргументов в Python: подробное руководство с примерами

Раздел: Python -> Функции

Основы: использование *args и **kwargs

В Python звездочка * перед именем параметра в определении функции позволяет собрать все переданные позиционные аргументы в кортеж. Две звездочки ** делают то же самое для именованных аргументов, помещая их в словарь. Это даёт возможность создавать функции, которые принимают произвольное количество входных данных.

def combined(*args, **kwargs):
    print(f"Позиционные: {args}")
    print(f"Именованные: {kwargs}")

combined(1, 2, 3, name="Анна", age=30)

аргументы print python (аргументы функции print в python)

Позиционные: (1, 2, 3)
Именованные: {'name': 'Анна', 'age': 30}

Python 3 аргументы (аргументы в python 3)

Цель: универсальность - функция не зависит от точного количества аргументов и может использоваться как обёртка для других функций.

Типичная ошибка

Если забыть звездочку, то args будет обычным параметром, а не кортежем переменной длины. Аналогично для kwargs. Возникает TypeError: функция ожидает один или два аргумента, а получает больше.


Как передать произвольное количество позиционных аргументов?

Параметр *args собирает все позиционные аргументы в кортеж. Имя args - соглашение, можно использовать любое, но звездочка обязательна.

def sum_all(*numbers):
    return sum(numbers)

print(sum_all(1, 2, 3, 4))

аргумент параметр python (аргументы и параметры в python)

10

аргумент класса python (аргументы класса python)

Цель: функции наподобие max(), sum() или логирование произвольного количества значений.

Проблема

При попытке передать именованные аргументы в *args они не попадут в кортеж. Если функция ожидает только *args, а передать именованный аргумент, возникнет TypeError.

Как принимать произвольное количество именованных аргументов?

Параметр **kwargs собирает все именованные аргументы в словарь. Имя kwargs - общепринятое.

def print_options(**options):
    for key, value in options.items():
        print(f"{key} = {value}")

print_options(host="localhost", port=8080, debug=True)

Python аргументы строки (аргументы строки в python (командная строка))

host = localhost
port = 8080
debug = True

аргумент метода python (аргументы метода python)

Цель: гибкая настройка, передача произвольного набора параметров в другие функции, создание конфигураций.

Типичная ошибка

Передача позиционного аргумента в функцию, которая принимает только **kwargs, вызовет TypeError. Также при повторении ключа в вызове возникнет ошибка дублирования.

Как одновременно обрабатывать позиционные и именованные аргументы?

Совместное использование *args и **kwargs позволяет перехватывать любые аргументы. Порядок в определении: сначала обычные параметры, затем *args, затем **kwargs.

def wrapper(f, *args, **kwargs):
    print("Вызов функции...")
    return f(*args, **kwargs)

def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

print(wrapper(greet, "Пётр", greeting="Привет"))

Python args (аргументы в python)

Вызов функции...
Привет, Пётр!

именованные аргументы функции python (именованные аргументы функции python)

Цель: декораторы, обёртки, передача произвольных аргументов из одной функции в другую.

Проблема

Если в определении поменять **kwargs и *args местами, Python выдаст SyntaxError. Также нельзя передать именованный аргумент с тем же именем, что у обычного параметра, дважды.

Как передать содержимое списка или словаря в функцию как отдельные аргументы?

Операторы * и ** при вызове функции распаковывают итерируемые объекты и словари.

def point(x, y, z):
    print(f"X={x}, Y={y}, Z={z}")

coords = [10, 20, 30]
point(*coords)

data = {"x": 1, "y": 2, "z": 3}
point(**data)

именованные аргументы python (именованные аргументы python)

X=10, Y=20, Z=30
X=1, Y=2, Z=3

количество аргументов функции python (количество аргументов функции python)

Цель: удобная передача элементов коллекции в функцию, особенно при работе с внешними данными.

Ошибка

Несоответствие количества элементов в списке числу параметров функции вызывает TypeError. В словаре ключи должны в точности совпадать с именами параметров, иначе ошибка.

Как заставить передавать некоторые аргументы только по имени?

После * в определении функции все параметры становятся keyword-only - их можно передать только как именованные.

def connect(host, *, port, timeout=30):
    print(f"Подключение к {host}:{port} с таймаутом {timeout}")

connect("localhost", port=8080)
# connect("localhost", 8080)  # TypeError

параметры и аргументы функции python (параметры и аргументы функции python)

Подключение к localhost:8080 с таймаутом 30

Python передать аргументы (передача аргументов в python)

Цель: явная спецификация параметров, повышение читаемости кода и предотвращение случайной передачи неверных значений.

Проблема

Попытка передать keyword-only аргумент позиционно вызывает TypeError. Это особенность, а не ошибка - её стоит учитывать при проектировании API.

Как сделать аргументы только позиционными?

Символ / в списке параметров (Python 3.8+) отделяет позиционные аргументы слева от него.

def subtract(a, b, /, c=0):
    return a - b - c

print(subtract(10, 3, 1))      # работает
print(subtract(10, 3, c=1))    # тоже работает
# print(subtract(a=10, b=3))   # TypeError

переменное количество аргументов python (переменное количество аргументов python)

6
6

Цель: защита от именованной передачи, возможность изменить имена параметров в будущем без нарушения совместимости.

Ошибка

При попытке передать позиционный аргумент по имени возникает TypeError. Это штатное поведение, но его нужно документировать.

- Python функция аргумент список (список как аргумент функции python)
- Python тип аргумента (тип аргумента в python)
- Python функция в качестве аргумента (функция как аргумент в python)

Расширенные примеры использования переменного количества аргументов

Пример 1: Декоратор для логирования вызовов

Декоратор, который принимает любую функцию и выводит её имя, аргументы и результат.

Пример
def log_calls(func):
    def wrapper(*args, **kwargs):
        args_repr = [repr(a) for a in args]
        kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]
        signature = ", ".join(args_repr + kwargs_repr)
        print(f"Вызов: {func.__name__}({signature})")
        result = func(*args, **kwargs)
        print(f"Результат: {result}")
        return result
    return wrapper

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

multiply(3, 4)
multiply(5, b=6)
Вызов: multiply(3, 4)
Результат: 12
Вызов: multiply(5, b=6)
Результат: 30

Пример 2: Функция произведение всех переданных чисел

Использование *args для вычисления произведения любого количества чисел.

Пример
def product(*args):
    if not args:
        return 1
    result = 1
    for num in args:
        result *= num
    return result

print(product(2, 3, 4))
print(product(10, 0.5, 6))
print(product())
24
30.0
1

Пример 3: Объединение словарей через **kwargs

Функция принимает несколько именованных аргументов и возвращает объединённый словарь.

Пример
def merge_dicts(**kwargs):
    return kwargs

d1 = {"a": 1, "b": 2}
d2 = {"c": 3, "d": 4}
merged = merge_dicts(**d1, **d2)
print(merged)
{'a': 1, 'b': 2, 'c': 3, 'd': 4}

Пример 4: Комбинирование всех видов параметров

Функция, использующая позиционные, *args, keyword-only и **kwargs.

Пример
def complex_func(a, b, *args, option=True, **kwargs):
    print(f"a={a}, b={b}")
    print(f"args: {args}")
    print(f"option: {option}")
    print(f"kwargs: {kwargs}")

complex_func(1, 2, 3, 4, option=False, verbose=True, mode='test')
a=1, b=2
args: (3, 4)
option: False
kwargs: {'verbose': True, 'mode': 'test'}

Пример 5: Распаковка кортежа и словаря при вызове

Комбинированная распаковка списка и словаря в одну функцию.

Пример
def show_config(host, port, debug, timeout):
    print(f"Server: {host}:{port}")
    print(f"Debug: {debug}, Timeout: {timeout}")

base = ["127.0.0.1", 3000]
opts = {"debug": True, "timeout": 60}
show_config(*base, **opts)
Server: 127.0.0.1:3000
Debug: True, Timeout: 60

Пример 6: Проверка типов аргументов в обёртке

Функция проверяет, что все переданные позиционные аргументы - числа, иначе выбрасывает исключение.

Пример
def require_numeric(func):
    def wrapper(*args, **kwargs):
        for arg in args:
            if not isinstance(arg, (int, float)):
                raise TypeError(f"Аргумент {arg} не является числом")
        return func(*args, **kwargs)
    return wrapper

@require_numeric
def add_all(*nums):
    return sum(nums)

print(add_all(1, 2, 3.5))
# print(add_all(1, "a", 2))  # TypeError
6.5

Пример 7: Использование *args и **kwargs в методе __init__ класса

Базовый класс, который принимает произвольные аргументы и сохраняет их как атрибуты.

Пример
class Config:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

cfg = Config(host='example.com', port=443, ssl=True)
print(cfg.host, cfg.port, cfg.ssl)
example.com 443 True

Пример 8: Анализ сигнатуры с помощью inspect

Получение информации о параметрах функции, определённой с *args и **kwargs.

Пример
import inspect

def example(a, b=10, *args, key=None, **kwargs):
    pass

sig = inspect.signature(example)
for name, param in sig.parameters.items():
    print(f"{name}: kind={param.kind.name}, default={param.default}")
a: kind=POSITIONAL_OR_KEYWORD, default=inspect._empty
b: kind=POSITIONAL_OR_KEYWORD, default=10
args: kind=VAR_POSITIONAL, default=inspect._empty
key: kind=KEYWORD_ONLY, default=None
kwargs: kind=VAR_KEYWORD, default=inspect._empty

Переменное количество аргументов Python - comments

En
переменное количество аргументов python (python)