← Назад к вопросам

Зачем нужен *args?

1.0 Junior🔥 181 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Зачем нужен *args?

*args используется в Python для передачи переменного количества позиционных аргументов функции. Это один из самых полезных инструментов при написании гибких и масштабируемых функций.

Основная концепция

*args преобразует все переданные позиционные аргументы в кортеж (tuple):

def print_all(*args):
    print(f"Тип: {type(args)}")
    print(f"Значение: {args}")
    for i, arg in enumerate(args):
        print(f"  arg[{i}] = {arg}")

print_all()                           # args = ()
print_all(1)                          # args = (1,)
print_all(1, 2, 3)                    # args = (1, 2, 3)
print_all("hello", 42, [1, 2, 3])    # args = ("hello", 42, [1, 2, 3])

1. Функции с переменным количеством аргументов

# ❌ Плохо — ограничено 3 параметрами
def sum_two(a, b):
    return a + b

sum_two(1, 2)        # OK
sum_two(1, 2, 3)     # TypeError!

# ✅ Хорошо — работает с любым количеством
def sum_all(*numbers):
    total = 0
    for num in numbers:
        total += num
    return total

sum_all(1, 2)           # 3
sum_all(1, 2, 3, 4, 5)  # 15
sum_all()               # 0

2. Проксирование аргументов другой функции

Частый случай при создании декораторов и обёрток:

# Функция, которую мы хотим обернуть
def calculate(a, b, operation='add'):
    if operation == 'add':
        return a + b
    elif operation == 'multiply':
        return a * b

# Декоратор с логированием
def log_calls(func):
    def wrapper(*args, **kwargs):
        print(f"Вызов функции {func.__name__}")
        print(f"  Аргументы: {args}")
        print(f"  Ключевые аргументы: {kwargs}")
        result = func(*args, **kwargs)  # Передаём все как есть
        print(f"  Результат: {result}")
        return result
    return wrapper

@log_calls
def calculate(a, b, operation='add'):
    if operation == 'add':
        return a + b
    elif operation == 'multiply':
        return a * b

calculate(5, 3)                      # Работает
calculate(5, 3, operation='multiply')  # Также работает

3. Функции форматирования и логирования

# Встроенная функция print использует *args
print("Hello", "World", 42, True)  # print(*args)
# Эквивалентно:
print(("Hello", "World", 42, True))

# Пример: функция для логирования
def log_info(prefix, *messages):
    """Логировать сообщения с префиксом"""
    output = f"[{prefix}] "
    output += " | ".join(str(msg) for msg in messages)
    print(output)

log_info("INFO", "Application started")
log_info("ERROR", "File not found", "Path: /etc/config.txt", "Code: 404")
log_info("DEBUG", "a", "b", "c", "d", "e")  # Любое количество

4. Распаковка списков и кортежей

# Распаковка при вызове функции
def greet(first, second, third):
    print(f"{first} {second} {third}")

names = ["Alice", "Bob", "Charlie"]
greet(*names)  # Распаковка списка в аргументы
# Эквивалентно: greet("Alice", "Bob", "Charlie")

# Практический пример:传递данные между функциями
def get_user_data():
    return "John", 30, "john@example.com"

def display_user(name, age, email):
    print(f"{name}, {age} лет, {email}")

data = get_user_data()
display_user(*data)  # Распаковка кортежа

5. Конкатенация аргументов

def concatenate(*args, separator=" "):
    """Объединить аргументы с разделителем"""
    return separator.join(str(arg) for arg in args)

concatenate("Hello", "World")           # "Hello World"
concatenate("a", "b", "c", separator="-")  # "a-b-c"
concatenate(1, 2, 3, separator=",")     # "1,2,3"

6. Создание функций с гибкой сигнатурой

class Logger:
    def __init__(self, prefix):
        self.prefix = prefix
    
    def log(self, *messages, level="INFO"):
        """Логировать с любым количеством сообщений"""
        full_message = " ".join(str(msg) for msg in messages)
        print(f"[{self.prefix}] [{level}] {full_message}")
    
    def debug(self, *messages):
        self.log(*messages, level="DEBUG")
    
    def error(self, *messages):
        self.log(*messages, level="ERROR")

# Использование
logger = Logger("APP")
logger.log("Server started", "listening on port 8000")
logger.debug("Variable x =", 42, "Variable y =", 3.14)
logger.error("Connection failed", "Host unreachable", "Retry in", 5, "seconds")

7. Работа с matplotlib и другими библиотеками

Много популярных библиотек используют *args:

import matplotlib.pyplot as plt

# matplotlib.plot использует *args для нескольких линий
x = [1, 2, 3, 4]
y1 = [1, 4, 2, 3]
y2 = [2, 3, 4, 1]
y3 = [3, 2, 1, 4]

plt.plot(x, y1, label='Line 1')
plt.plot(x, y2, label='Line 2')
plt.plot(x, y3, label='Line 3')

# Или так:
plt.plot(x, y1, x, y2, x, y3)

# Эквивалентно вызову с *args внутри
def plot(*args, **kwargs):
    for i in range(0, len(args), 2):
        print(f"Линия {i//2}: {args[i]} -> {args[i+1]}")

8. Функции со звёздочкой в разных позициях

# ✅ Звёздочка в начале
def func1(*args):
    print(args)

func1(1, 2, 3)  # (1, 2, 3)

# ✅ Звёздочка с обычными параметрами
def func2(first, *args):
    print(f"First: {first}, Rest: {args}")

func2(1, 2, 3, 4)  # First: 1, Rest: (2, 3, 4)

# ✅ Звёздочка с именованными параметрами (именованные ПОСЛЕ *args)
def func3(*args, prefix="DEFAULT"):
    print(f"Prefix: {prefix}, Args: {args}")

func3(1, 2, 3, prefix="CUSTOM")  # Prefix: CUSTOM, Args: (1, 2, 3)

# ✅ Когда нужны обязательные параметры после *args
def func4(a, b, *args, separator="-"):
    print(f"a={a}, b={b}, rest={args}, sep={separator}")

func4(1, 2, 3, 4, 5, separator="_")  # a=1, b=2, rest=(3, 4, 5), sep=_

9. Сравнение *args и **kwargs

# *args — позиционные аргументы (кортеж)
# **kwargs — именованные аргументы (словарь)

def flexible(*args, **kwargs):
    print(f"args: {args}")
    print(f"kwargs: {kwargs}")

flexible(1, 2, 3)  # args: (1, 2, 3), kwargs: {}
flexible(a=1, b=2)  # args: (), kwargs: {'a': 1, 'b': 2}
flexible(1, 2, a=3, b=4)  # args: (1, 2), kwargs: {'a': 3, 'b': 4}

# Практический пример
def create_request(*args, **kwargs):
    """Создать HTTP запрос с любыми параметрами"""
    return {
        "positional": args,
        "keyword": kwargs
    }

request = create_request("GET", "https://api.example.com", timeout=5, retries=3)
print(request)
# {'positional': ('GET', 'https://api.example.com'), 'keyword': {'timeout': 5, 'retries': 3}}

10. Вложенные функции с *args

def outer_function(*args):
    def inner_function():
        return sum(args)  # Доступ к args из внешней функции
    
    return inner_function

# Использование
f = outer_function(1, 2, 3, 4, 5)
print(f())  # 15

11. Анти-паттерны

# ❌ Плохо — путаница с семантикой
def confusing_function(*args):
    a = args[0]      # Неясно, что это должно быть
    b = args[1]      # Хрупкий код
    c = args[2]
    return a + b + c

# ✅ Хорошо — ясная семантика
def clear_function(a, b, c):
    return a + b + c

# ✅ Или если нужна гибкость
def flexible_function(*numbers):
    if len(numbers) < 3:
        raise ValueError("Нужно минимум 3 параметра")
    return sum(numbers[:3])

# ❌ Плохо — неинформативное использование *args
def mystery_function(*args):
    return args[0] * args[1] + args[2] / args[3]

# ✅ Хорошо — документируем
def calculate_formula(numerator, *denominators):
    """Разделить numerator на произведение всех denominators"""
    result = numerator
    for denom in denominators:
        result /= denom
    return result

Выводы

*args используется для:

  • Переменного количества параметров (print, max, min)
  • Проксирования аргументов (декораторы, обёртки)
  • Распаковки последовательностей (list, tuple)
  • Гибких функций форматирования (логирование, строки)
  • API, где не известно заранее количество параметров

Ключевая идея: используй *args когда аргументы однородны и их количество может варьироваться. Если аргументы разных типов и фиксированного количества, явно опиши параметры функции.

Зачем нужен *args? | PrepBro