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

Что такое * и ** в Python?

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

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

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

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

Операторы * и ** в Python: полный разбор

Это один из самых важных и многофункциональных операторов в Python. Расскажу обо всех применениях.

1. Распаковка итерируемых объектов (*)

В функциях:

def greet(a, b, c):
    print(f"{a}, {b}, {c}")

args = ['Alice', 'Bob', 'Charlie']
greet(*args)  # Распаковать список как отдельные аргументы
# Результат: Alice, Bob, Charlie

В списках и кортежах:

list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = [*list1, *list2]
print(combined)  # [1, 2, 3, 4, 5, 6]

# Распаковка в разных местах
first, *middle, last = [1, 2, 3, 4, 5]
print(middle)  # [2, 3, 4]

2. Распаковка словарей ()**

В функциях:

def print_person(name, age, city):
    print(f"{name}, {age} лет, из {city}")

kwargs = {'name': 'Алиса', 'age': 30, 'city': 'Москва'}
print_person(**kwargs)
# Результат: Алиса, 30 лет, из Москва

В словарях:

dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}
merged = {**dict1, **dict2}
print(merged)  # {'a': 1, 'b': 2, 'c': 3, 'd': 4}

# Переопределение значений
config_default = {'debug': False, 'port': 8000}
config_custom = {'debug': True}
config = {**config_default, **config_custom}
print(config)  # {'debug': True, 'port': 8000}

3. *Сбор аргументов в функциях (args)

def sum_all(*numbers):
    """Сложить произвольное количество чисел"""
    return sum(numbers)

print(sum_all(1, 2, 3, 4, 5))  # 15
print(sum_all(10, 20))  # 30

# args — это кортеж
def print_args(*args):
    print(f"Тип: {type(args)}")
    print(f"Значение: {args}")

print_args('a', 'b', 'c')
# Тип: <class 'tuple'>
# Значение: ('a', 'b', 'c')

4. **Сбор именованных аргументов (kwargs)

def build_profile(name, age, **kwargs):
    """Построить профиль с дополнительными полями"""
    profile = {'name': name, 'age': age}
    profile.update(kwargs)  # Добавить все остальные ключ-значение
    return profile

result = build_profile(
    'Алиса',
    30,
    city='Москва',
    job='Engineer',
    hobbies=['reading', 'coding']
)
print(result)
# {'name': 'Алиса', 'age': 30, 'city': 'Москва', 'job': 'Engineer', 'hobbies': [...]}

5. **Комбинация *args и kwargs

def flexible_function(a, b, *args, **kwargs):
    print(f"Позиционные: a={a}, b={b}")
    print(f"*args: {args}")
    print(f"**kwargs: {kwargs}")

flexible_function(1, 2, 3, 4, 5, name='Alice', city='NYC')
# Позиционные: a=1, b=2
# *args: (3, 4, 5)
# **kwargs: {'name': 'Alice', 'city': 'NYC'}

Важно: порядок параметров

# ✅ Правильно
def good(a, b, *args, c=None, **kwargs):
    pass

# ❌ Неправильно
def bad(*args, c=None, b, **kwargs):
    pass  # SyntaxError

6. Распаковка в операции присваивания

# Базовое распаковывание
a, b, c = [1, 2, 3]

# С игнорированием значений
first, _, third = [1, 2, 3]
print(first, third)  # 1, 3

# Распаковка нескольких
first, *middle, last = [1, 2, 3, 4, 5]
print(first, middle, last)  # 1, [2, 3, 4], 5

# Обмен значений
a, b = 1, 2
a, b = b, a  # Без временной переменной!
print(a, b)  # 2, 1

7. Распаковка в декораторах

def log_calls(func):
    def wrapper(*args, **kwargs):
        print(f"Вызов: {func.__name__}({args}, {kwargs})")
        result = func(*args, **kwargs)
        print(f"Результат: {result}")
        return result
    return wrapper

@log_calls
def add(a, b):
    return a + b

add(5, 10)
# Вызов: add((5, 10), {})
# Результат: 15

8. Распаковка в интроспекции и рефлексии

import inspect

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

sig = inspect.signature(example)
print(sig)  # (a, b, *args, c=None, **kwargs)

# Получить параметры
for param_name, param in sig.parameters.items():
    print(f"{param_name}: {param.kind}")

9. Распаковка в функциях высшего порядка

# Partial application через распаковку
def multiply(a, b):
    return a * b

numbers = [3, 4]
result = multiply(*numbers)
print(result)  # 12

# Применение функции с разными наборами аргументов
funcs_and_args = [
    (sum, [1, 2, 3]),
    (max, [10, 20, 30]),
    (min, [5, 3, 8])
]

results = [func(*args) for func, args in funcs_and_args]
print(results)  # [6, 30, 3]

10. Тонкости и частые ошибки

# ❌ Ошибка: *args должен быть перед **kwargs
def wrong(*kwargs, **args):  # SyntaxError
    pass

# ❌ Ошибка: нельзя использовать * дважды
result = [*list1, *list2, *list3]  # OK в списках

# ✅ Но работает, если список — элемент tuple
def func(*args):
    return args

result = func(*[1, 2, 3], *[4, 5])  # OK: (1, 2, 3, 4, 5)

# Распаковка в именованных аргументах: ключи должны совпадать
def greet(name, greeting):
    return f"{greeting}, {name}!"

kwargs = {'greeting': 'Hello', 'name': 'Alice'}
print(greet(**kwargs))  # Hello, Alice!

# ❌ KeyError: лишний ключ в kwargs
kwargs = {'name': 'Alice', 'age': 30}
greet(**kwargs)  # TypeError: got an unexpected keyword argument 'age'

Практический пример: гибкий API

class APIClient:
    def __init__(self, base_url, **config):
        self.base_url = base_url
        self.timeout = config.get('timeout', 30)
        self.retries = config.get('retries', 3)
        self.headers = config.get('headers', {})
    
    def request(self, method, endpoint, *args, **kwargs):
        """Гибкий метод для любых запросов"""
        url = f"{self.base_url}{endpoint}"
        # args для позиционных параметров (редко)
        # kwargs для параметров запроса
        params = kwargs.pop('params', {})
        headers = {**self.headers, **kwargs.pop('headers', {})}
        
        return self._make_request(
            method,
            url,
            params=params,
            headers=headers,
            **kwargs  # Остальные параметры (data, json, etc)
        )

# Использование
client = APIClient(
    'https://api.example.com',
    timeout=60,
    headers={'Authorization': 'Bearer token'}
)

data = client.request(
    'POST',
    '/users',
    json={'name': 'Alice'},
    headers={'X-Request-ID': '123'}
)

Итоги

  • * распаковывает итерируемые (списки, кортежи) в позиционные аргументы
  • ** распаковывает словари в именованные аргументы (ключ=значение)
  • *args собирает переменное количество позиционных аргументов в кортеж
  • **kwargs собирает переменное количество именованных аргументов в словарь
  • Порядок: обычные параметры → *args → именованные с дефолтами → **kwargs
  • Распаковка работает везде: в функциях, списках, словарях, присваивании

Эти операторы — ключ к написанию гибких, масштабируемых Python функций и хорошему пониманию того, как работают встроенные функции типа print(), zip(), map().