Python: уроки, справочник и задачи

Аргументы функций в Python: виды и правила передачи

Раздел: Функции Python · Обновлено 31.10.2026

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

Аргументы функций в Python: виды и правила передачи
Фото: Martin Vorel / CC BY-SA 4.0, Wikimedia Commons
Содержание статьи
  1. Параметры и аргументы: в чем разница
  2. Позиционные аргументы
  3. Значения по умолчанию
    1. Ловушка с изменяемым значением
  4. Именованные аргументы при вызове
  5. Переменное число аргументов: *args и **kwargs
    1. Позиционные значения в *args
    2. Именованные значения в **kwargs
    3. Распаковка при вызове
  6. Только позиционные и только именованные параметры
  7. Порядок параметров в определении функции
  8. Частые вопросы
    1. Передаются аргументы по значению или по ссылке?
    2. Можно ли назвать параметры не args и kwargs?
    3. Как узнать, какие аргументы принимает функция?
    4. Сколько аргументов можно передать в функцию?

Параметры и аргументы: в чем разница

Параметр это имя в определении функции, аргумент это конкретное значение, переданное при вызове. В примере ниже name и message являются параметрами, а строки "Тимур" и "Доброе утро" аргументами.

def greet(name, message):
    print(f"Привет, {name}! {message}")

greet("Тимур", "Доброе утро")
# Привет, Тимур! Доброе утро

В обиходе слова часто смешивают, и в сообщениях об ошибках Python тоже пишет argument. Различие полезно помнить, когда читаете документацию: там описываются параметры, а передаете вы аргументы. Основы объявления функций через def и return разобраны в статье о функциях Python 3.

Позиционные аргументы

Самый простой способ: значения сопоставляются с параметрами по порядку. Первый аргумент попадает в первый параметр, второй во второй. Если количество не совпадает, вызов завершается ошибкой еще до выполнения тела функции.

def power(base, exp):
    return base ** exp

print(power(2, 10))  # 1024
print(power(10, 2))  # 100

power(2)
# TypeError: power() missing 1 required positional argument: 'exp'

Порядок здесь несет смысл: power(2, 10) и power(10, 2) дают разные результаты. Если параметров больше трех, позиционный вызов становится трудно читать, и лучше перейти к именованным аргументам.

Значения по умолчанию

Параметру можно задать значение, которое используется, если аргумент не передали. Такие параметры становятся необязательными.

def greet(name, message="Доброе утро"):
    print(f"{name}, {message}")

greet("Тимур")               # Тимур, Доброе утро
greet("Мария", "как дела?")  # Мария, как дела?

Параметры со значением по умолчанию должны идти после обязательных. Запись def greet(message="Привет", name) не скомпилируется: в Python 3.12 будет SyntaxError: parameter without a default follows parameter with a default.

Ловушка с изменяемым значением

Значение по умолчанию вычисляется один раз, в момент определения функции. Если это список или словарь, все вызовы без аргумента работают с одним и тем же объектом, и данные накапливаются между вызовами.

def add_item(item, bucket=[]):
    bucket.append(item)
    return bucket

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2]  неожиданно

def add_item_safe(item, bucket=None):
    if bucket is None:
        bucket = []
    bucket.append(item)
    return bucket

print(add_item_safe(1))  # [1]
print(add_item_safe(2))  # [2]

Правило простое: для изменяемых значений по умолчанию ставьте None и создавайте объект внутри функции.

Именованные аргументы при вызове

Любой обычный параметр можно передать по имени в виде имя=значение. Тогда порядок не важен, а вызов читается без заглядывания в определение функции.

def connect(host, port=5432, timeout=10):
    print(host, port, timeout)

connect("db.local", timeout=3)           # db.local 5432 3
connect(port=6000, host="localhost")     # localhost 6000 10

Смешивать способы можно, но позиционные аргументы всегда идут первыми. Вызов connect(host="db", 5432) дает SyntaxError: positional argument follows keyword argument. Еще одна частая ошибка: передать значение одному параметру дважды, например connect("db", host="x"), что приводит к TypeError: connect() got multiple values for argument 'host'.

Переменное число аргументов: *args и **kwargs

Когда заранее неизвестно, сколько значений придет, используют параметры со звездочками. Имена args и kwargs всего лишь соглашение, значение имеет только количество звездочек.

Позиционные значения в *args

Параметр с одной звездочкой собирает все лишние позиционные аргументы в кортеж. Если их нет, кортеж будет пустым.

def total(*numbers):
    print(type(numbers), numbers)
    return sum(numbers)

print(total(3, 5, 7))
# <class 'tuple'> (3, 5, 7)
# 15
print(total())
# <class 'tuple'> ()
# 0

Именованные значения в **kwargs

Две звездочки собирают лишние именованные аргументы в словарь, где ключ это имя, а значение это переданный объект.

def build_profile(name, **info):
    profile = {"name": name}
    profile.update(info)
    return profile

print(build_profile("Анна", city="Казань", age=27))
# {'name': 'Анна', 'city': 'Казань', 'age': 27}

Распаковка при вызове

Звездочки работают и в обратную сторону. Перед списком или кортежем * раскладывает элементы по позициям, перед словарем ** превращает пары в именованные аргументы.

def point(x, y, z):
    return f"({x}, {y}, {z})"

coords = [1, 2, 3]
opts = {"x": 0, "y": 5, "z": 9}
print(point(*coords))  # (1, 2, 3)
print(point(**opts))   # (0, 5, 9)

Сочетание *args и **kwargs позволяет написать обертку, которая принимает что угодно и передает дальше без изменений. На этом построены декораторы в Python.

Только позиционные и только именованные параметры

В сигнатуре можно явно запретить один из способов передачи. Все параметры левее символа / принимаются только по позиции (доступно с Python 3.8). Все параметры правее одиночной * или *args принимаются только по имени.

def resize(image, /, width, height, *, keep_ratio=True):
    return image, width, height, keep_ratio

print(resize("a.png", 800, height=600))
# ('a.png', 800, 600, True)

resize(image="a.png", width=800, height=600)
# TypeError: resize() got some positional-only arguments passed as keyword arguments: 'image'

resize("a.png", 800, 600, False)
# TypeError: resize() takes 3 positional arguments but 4 were given

Только именованные параметры подходят для флагов: вызов resize(img, 800, 600, keep_ratio=False) понятен без документации, а False четвертым аргументом ничего не объясняет. Только позиционные нужны, когда имя параметра может поменяться в будущем и не должно стать частью интерфейса. Многие встроенные функции так устроены, например len(obj, /).

Порядок параметров в определении функции

Если в одной сигнатуре встречаются разные виды параметров, они должны идти строго в таком порядке. Нарушение порядка вызывает SyntaxError.

ПозицияВидПример
1Только позиционные, до /a, /
2Обычные, без значения по умолчаниюb
3Обычные со значением по умолчаниюc=0
4Переменные позиционные*args
5Только именованныеd, e=1
6Переменные именованные**kwargs
def full(a, /, b, c=0, *args, d, e=1, **kwargs):
    print(a, b, c, args, d, e, kwargs)

full(1, 2, 3, 4, 5, d=6, f=7)
# 1 2 3 (4, 5) 6 1 {'f': 7}

В реальном коде все шесть видов сразу встречаются редко, но таблица помогает разобраться в любой чужой сигнатуре. Подробнее правила описаны в разделе More on Defining Functions официального учебника.

Частые вопросы

Короткие ответы на вопросы, которые чаще всего задают при изучении параметров функций.

Передаются аргументы по значению или по ссылке?

Ни то, ни другое в классическом смысле: функция получает ссылку на тот же объект. Изменяемый объект, например список, можно поменять внутри функции, и изменения будут видны снаружи. Присваивание параметру нового значения на внешнюю переменную не влияет.

Можно ли назвать параметры не args и kwargs?

Да, работают любые имена: *values, **options. Имена args и kwargs приняты для случаев, когда у значений нет более точного смысла.

Как узнать, какие аргументы принимает функция?

Вызовите help(func) или посмотрите inspect.signature(func). Для своих функций полезно добавлять аннотации типов: редактор будет подсказывать параметры при вызове.

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

Практического ограничения нет. Если параметров больше пяти-шести, это повод сгруппировать их в словарь, dataclass или разбить функцию на несколько.