Переменное количество аргументов в 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. Это штатное поведение, но его нужно документировать.
Расширенные примеры использования переменного количества аргументов
Пример 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)) # TypeError6.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