Содержание
- Что означает unexpected argument и почему Python его отвергает
- Дословный трейсбек: что печатает Python 3.14.3
- Подсказка Did you mean: с какой версии Python сам называет верное имя
- Причины возникновения unexpected argument: девять сценариев, три формы сообщения
- Имя функции в ошибке отличается от имени в вашем вызове
- Когда unexpected argument прилетает после обновления библиотеки
- Как исправить ошибку unexpected argument: пять починок, каждая прогнана
- Декоратор, который возвращает контроль имен при использовании **kwargs
- Схема разбора: от текста ошибки к починке за три шага
- Что стало с сообщением keyword can’t be an expression
- Чек-лист: как быстро закрыть unexpected argument
- Частые вопросы про unexpected argument
Что означает ошибка TypeError: function got an unexpected keyword argument в Python?
Черновик готовит редакция с помощью ИИ. За стандарт издания отвечает главный редактор — Валерий Курземнек.
TypeError: got an unexpected keyword argument означает ровно одно: имя, переданное при вызове, в сигнатуре функции отсутствует. Python сопоставляет ключевые аргументы с параметрами определения по имени и отвергает всё лишнее. Починка — один шаг из трёх: привести имя к сигнатуре, принять лишние ключи через **kwargs или отфильтровать словарь перед распаковкой. Начиная с Python 3.13 интерпретатор сам называет правильное имя в тексте ошибки.
- Сообщение приходит на этапе вызова: тело функции не выполнялось ни разу.
- Подсказка
Did you mean 'name'?появляется, когда у параметра похожее имя. - Имя функции в тексте ошибки может отличаться от имени, которое вы написали в коде.
- Тот же класс ошибки даёт распаковка
**dictс лишним ключом и вызов после обновления библиотеки. - Параметры до
/дают другое сообщение —got some positional-only arguments passed as keyword arguments.
Что означает unexpected argument и почему Python его отвергает
Два повода, с которых начинается разбор. Первый — неправильное имя ключевого аргумента: в вызове стоит nam, в определении функции name. Второй — использование ключевых аргументов без поддержки произвольных имён: вызов с лишним ключом у функции, где **kwargs не объявлен. Прогон из раздела «Причины возникновения unexpected argument» показывает ещё семь поводов, и механика у всех одна. Ключевой аргумент — это пара «имя=значение» в вызове. Интерпретатор берёт имя из вызова и ищет параметр с таким же именем в определении функции. Совпадения нет — вызов прерывается до входа в тело, и наружу выходит TypeError. Документация Python описывает этот класс исключений дословно так: «Raised when an operation or function is applied to an object of inappropriate type. The associated value is a string giving details about the type mismatch».
Отсюда первое практическое следствие: трейсбек указывает на строку вызова, а внутри функции ничего не исполнялось. Переменные, которые вы там ожидали увидеть отладчиком, ещё не созданы. Разбор всегда начинается с сигнатуры, и полезно помнить разницу между функциями и методами в Python: у метода первым параметром стоит self, и счёт «лишних» ключей у него сдвинут.
Второе следствие: сообщение говорит об именах. Значение аргумента интерпретатор на этом этапе даже не смотрит, тип проверять некому. Поэтому приводить строки к числам и менять порядок аргументов бесполезно — пока имя расходится с параметром, результат тот же.
Дословный трейсбек: что печатает Python 3.14.3
Ниже прогон на Windows-сборке CPython 3.14.3 (tags/v3.14.3:323c59a, Feb 3 2026, MSC v.1944 64 bit). Файл из пяти строк, вызов с опечаткой в имени параметра:
import sys
print(sys.version)
def greet(name):
print(f"Hello, {name}")
greet(nam="Alice")
Вывод интерпретатора целиком, без сокращений:
3.14.3 (tags/v3.14.3:323c59a, Feb 3 2026, 16:04:56) [MSC v.1944 64 bit (AMD64)]
Traceback (most recent call last):
File "t1.py", line 7, in <module>
greet(nam="Alice")
~~~~~^^^^^^^^^^^^^
TypeError: greet() got an unexpected keyword argument 'nam'. Did you mean 'name'?
Читать этот вывод стоит снизу вверх. Последняя строка называет функцию (greet), проблемное имя ('nam') и готовую замену ('name'). Строка с тильдами и «крышками» под кодом — точные координаты: тильды покрывают вызываемый объект, крышки — скобки с аргументами. Когда в одной строке два-три вложенных вызова, эта разметка показывает, какой именно из них упал.
Порядок вывода говорит о том же: строка с версией напечаталась, строка Hello — нет. Программа дошла до вызова и остановилась на нём.
Подсказка Did you mean: с какой версии Python сам называет верное имя
Строка Did you mean 'name'? в тексте ошибки — это готовый ответ, который остаётся подставить в вызов. Её добавили в CPython 3.13. Официальный разбор новшеств Python 3.13 формулирует это дословно: «The error message now tries to suggest the correct keyword argument when an incorrect keyword argument is passed to a function», и приводит пример со стандартным методом:
>>> "Better error messages".split(max_split=1)
Traceback (most recent call last):
File "<python-input-0>", line 1, in <module>
"Better error messages".split(max_split=1)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
TypeError: split() got an unexpected keyword argument 'max_split'. Did you mean 'maxsplit'?
Практический вывод для диагностики: если вы видите unexpected argument без хвоста «Did you mean», возможны два случая. Первый — интерпретатор старше 3.13, и подсказку печатать просто нечем. Второй — версия свежая, а похожего имени в сигнатуре нет вовсе: параметр отсутствует целиком, переименование тут ни при чём. Различить их помогает одна команда в терминале: python -V.
Разница меняет план починки. На версиях до 3.13 сигнатуру приходится смотреть руками. На 3.13 и выше отсутствие подсказки само по себе информативно: гипотезу «опечатка» можно закрывать и переходить к причинам, по которым параметра нет вовсе — другая версия библиотеки, другой объект, другой класс.
Причины возникновения unexpected argument: девять сценариев, три формы сообщения
Чтобы понять, на что вообще похож этот TypeError, мы собрали скрипт из девяти сценариев и прогнали его одним запуском на Python 3.14.3. Прибор напечатал: сценариев 9, различных форм сообщения 3, подсказка «Did you mean» — в 3 случаях из 9.
| Сценарий | Дословный текст ошибки |
|---|---|
| Опечатка в имени параметра | TypeError: greet() got an unexpected keyword argument 'nam'. Did you mean 'name'? |
| Имени нет в сигнатуре | TypeError: calculate() got an unexpected keyword argument 'z' |
Распаковка словаря **d |
TypeError: calculate() got an unexpected keyword argument 'z' |
Параметры до / переданы по имени |
TypeError: posonly() got some positional-only arguments passed as keyword arguments: 'a, b' |
Опечатка в keyword-only параметре после * |
TypeError: kwonly() got an unexpected keyword argument 'moode'. Did you mean 'mode'? |
Встроенная функция sorted |
TypeError: sort() got an unexpected keyword argument 'keys'. Did you mean 'key'? |
Наследование через super().__init__(**kw) |
TypeError: Base.__init__() got an unexpected keyword argument 'nmae' |
functools.partial |
TypeError: calculate() got an unexpected keyword argument 'z' |
Сгенерированный __init__ у dataclass |
TypeError: P.__init__() got an unexpected keyword argument 'z' |
Из таблицы видно главное для диагностики: восемь сценариев из девяти дают одну и ту же формулировку про keyword argument, и различает их только имя функции слева. Девятый выпадает отдельным текстом про positional-only — это другая причина и другая починка.
Имя функции в ошибке отличается от имени в вашем вызове
Неочевидная ловушка этого TypeError: слева от «got an unexpected keyword argument» стоит имя того, кто реально принимал аргументы, и оно совпадает с написанным в коде далеко не всегда. Два случая из нашего прогона на Python 3.14.3.
Встроенная функция. Вызов sorted([3,1,2], keys=None) отвечает так:
TypeError: sort() got an unexpected keyword argument 'keys'. Did you mean 'key'?
В коде написано sorted, в ошибке — sort. Грепать проект по слову sort в такой ситуации бессмысленно. Верный шаг — спросить сигнатуру у самого интерпретатора: inspect.signature(sorted) печатает (iterable, /, *, key=None, reverse=False), и правильное имя key видно сразу.
Наследование. Класс-наследник принимает **kw и передаёт их дальше:
class Base:
def __init__(self, name): ...
class Child(Base):
def __init__(self, **kw):
super().__init__(**kw)
Child(nmae="x")
Результат прогона:
TypeError: Base.__init__() got an unexpected keyword argument 'nmae'
Вызывали Child, а претензию предъявляет Base.__init__, потому что **kw у наследника принимает всё подряд и отдаёт проблему выше по цепочке. В трейсбеке при этом видно два кадра: строку с Child(nmae="x") и строку с super().__init__(**kw). Внутри класса такие вещи легче ловить, когда сигнатуры дандер-методов перед глазами — например, при реализации методов __add__() и __radd__() действует то же правило совпадения имён.
Правило для обоих случаев: имя из сообщения — это подсказка, где искать определение, а строка трейсбека выше показывает, где стоит вызов.
Когда unexpected argument прилетает после обновления библиотеки
Код не менялся, а вызов вдруг падает — типичный сюжет после pip install -U. Параметр, который библиотека принимала в прошлой версии, в новой убрали или переименовали. Мы воспроизвели это у себя: один и тот же вызывающий файл и две версии модуля mailer, отличающиеся одним параметром.
# v1/mailer.py def send(to, text, use_context=True): ... # v2/mailer.py def send(to, text): ... # caller.py import mailer print(mailer.send(to="a@b.ru", text="hi", use_context=True))
Прогон на Python 3.14.3 с первой версией в sys.path даёт v1 -> a@b.ru: hi (use_context=True). Тот же файл со второй версией:
Traceback (most recent call last):
File "caller.py", line 4, in <module>
print(mailer.send(to="a@b.ru", text="hi", use_context=True))
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: send() got an unexpected keyword argument 'use_context'
Подсказки «Did you mean» здесь нет, и это диагностический признак: похожего имени в новой сигнатуре не осталось, поэтому подставлять интерпретатору нечего. Порядок разбора такой: pip show имя_пакета покажет установленную версию, inspect.signature(mailer.send) — реальный набор параметров, changelog библиотеки — под каким именем параметр живёт теперь.
Риск выше там, где библиотека меняется быстро: обёртки вокруг API нейросетей, клиенты мессенджеров, SDK платёжных систем — у них сигнатуры переезжают между мажорными версиями. Если вы собираете Telegram-бота на Python и OpenAI, привычка сверять сигнатуру с установленной версией экономит вечер.
Как исправить ошибку unexpected argument: пять починок, каждая прогнана
Ниже рабочие варианты. Каждый мы запустили одним файлом и приводим фактический вывод интерпретатора, чтобы вариант можно было скопировать и проверить у себя.
import inspect, sys
print("Python", sys.version.split()[0])
# 1. Привести имя к сигнатуре
def greet(name): return f"Hello, {name}"
print("fix1:", greet(name="Alice"))
# 2. Принять лишние ключи через **kwargs
def calculate(x, y, **kwargs): return x + y, kwargs
print("fix2:", calculate(x=5, y=3, z=2))
# 3. Отфильтровать словарь по сигнатуре ДО распаковки
def calc2(x, y): return x + y
data = {"x": 5, "y": 3, "z": 2, "source": "crm"}
allowed = set(inspect.signature(calc2).parameters)
clean = {k: v for k, v in data.items() if k in allowed}
print("fix3: отброшено", sorted(set(data) - allowed), "->", calc2(**clean))
# 4. Позиционно-только параметры передать позиционно
def posonly(a, b, /): return a + b
print("fix4:", posonly(1, 2))
# 5. Сверить сигнатуру установленной версии
print("fix5:", inspect.signature(str.split))
Фактический вывод:
Python 3.14.3
fix1: Hello, Alice
fix2: (8, {'z': 2})
fix3: отброшено ['source', 'z'] -> 8
fix4: 3
fix5: (self, /, sep=None, maxsplit=-1)
Третий вариант лечит причину, когда аргументы приходят из внешних данных: JSON от API, строка базы, форма. Словарь фильтруется по реальным параметрам функции, лишние ключи отбрасываются осознанно, и распаковка **clean больше не может принести неожиданное имя. В нашем прогоне отброшены source и z, результат вызова — 8.
Второй вариант с **kwargs удобен, но у него есть цена: функция перестаёт сообщать об опечатках вовсе. Вызов calculate(x=5, y=3, zz=2) после такой правки пройдёт молча, и ошибка всплывёт дальше по коду в виде неверного результата. Документация Python описывает поведение **name так: «it receives a dictionary containing all keyword arguments except for those corresponding to a formal parameter».
Декоратор, который возвращает контроль имен при использовании **kwargs
У починки через **kwargs есть цена: функция проглатывает любые имена, включая неправильное, и unexpected argument больше не возникает даже там, где он был бы полезен. Декоратор снимает эту цену — он сверяет ключи вызова с сигнатурой и падает раньше, с внятным текстом. Ниже пример использования, прогнанный на Python 3.14.3.
import inspect, functools, sys
print("Python", sys.version.split()[0])
def strict_kwargs(func):
params = inspect.signature(func).parameters
named = {n for n, p in params.items()
if p.kind in (p.POSITIONAL_OR_KEYWORD, p.KEYWORD_ONLY)}
@functools.wraps(func)
def wrapper(*args, **kwargs):
extra = sorted(set(kwargs) - named)
if extra:
raise TypeError(
f"{func.__name__}(): unexpected keyword arguments {extra}; "
f"expected {sorted(named)}")
return func(*args, **kwargs)
return wrapper
@strict_kwargs
def calculate(x, y, **kwargs):
return x + y
print("ok:", calculate(x=5, y=3))
try:
calculate(x=5, y=3, z=2)
except TypeError as e:
print("TypeError:", e)
Фактический вывод прогона:
Python 3.14.3 ok: 8 TypeError: calculate(): unexpected keyword arguments ['z']; expected ['x', 'y']
Здесь есть тонкость, из-за которой наивная версия декоратора врёт. Проверка наличия ключей идёт по именованным параметрам: из signature().parameters берутся только виды POSITIONAL_OR_KEYWORD и KEYWORD_ONLY. Сам **kwargs тоже лежит в parameters под именем kwargs, и без фильтра по виду параметра он попадает в список ожидаемых имен — в первом прогоне мы получили именно такое сообщение, с посторонним 'kwargs' в перечне.
Тот же приём годится для логирования и для проверки типизации: обёртка видит и сигнатуру, и фактические аргументы вызова, поэтому управление ими целиком лежит в декораторе, а тело функции остаётся без изменения.
Схема разбора: от текста ошибки к починке за три шага

Алгоритм, которым мы разбирали девять сценариев прогона на Python 3.14.3, укладывается в три вопроса к самому тексту ошибки.
Шаг 1. Прочитать текст после двоеточия. Формулировка got some positional-only arguments passed as keyword arguments означает параметры до / и лечится передачей позиционно. Формулировка got an unexpected keyword argument ведёт к шагу 2.
Шаг 2. Посмотреть, есть ли хвост Did you mean. Есть — это опечатка, имя из подсказки подставляется в вызов, разбор закончен. Нет — на 3.13 и выше это значит, что похожего параметра в сигнатуре не нашлось, и разбор идёт на шаг 3.
Шаг 3. Спросить сигнатуру у интерпретатора. inspect.signature(объект) печатает реальный набор параметров той версии, которая установлена сейчас. Дальше решение: править имя в вызове, фильтровать входной словарь или обновлять код под новую сигнатуру библиотеки.
Три шага закрывают и случаи, где имя в ошибке не совпадает с именем вызова: сигнатуру спрашивают у объекта из кода, а интерпретатор сам показывает, что у него внутри.
Что стало с сообщением keyword can’t be an expression
Запрос «keyword can t be an expression» до сих пор живёт в подсказках поиска, хотя современный интерпретатор такого текста уже не печатает. Это соседняя ошибка: она возникает, когда слева от знака «равно» в вызове стоит выражение — атрибут, индекс, строковый литерал — вместо простого имени параметра. Мы прогнали обе типовые формы на Python 3.14.3.
def f(name=None): pass
obj = type("O", (), {})()
f(obj.name="x")
File "t4.py", line 3
f(obj.name="x")
^^^^^^^^^
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
То же самое со строковым литералом вместо имени параметра:
f("name"="x")
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
И третья родственная формулировка — повтор одного имени в вызове:
File "t6.py", line 2
f(a=1, a=2)
^^^
SyntaxError: keyword argument repeated: a
Ключевое отличие от unexpected argument — момент срабатывания. Все три сообщения выдаёт парсер до запуска программы, поэтому ни одна строка файла не выполнится, даже если ошибка стоит в самом конце. TypeError про unexpected argument, наоборот, возникает уже во время работы, и предыдущие строки к этому моменту отработали. Подробнее о том, как читать сообщения парсера, — в разборе ошибки SyntaxError: invalid syntax.
Имена ключевых аргументов подчиняются правилам идентификаторов: буквы, цифры и подчёркивание, без точек и кавычек. Передать значение по вычисляемому ключу можно только через словарь и распаковку: f(**{"name": "x"}).
Чек-лист: как быстро закрыть unexpected argument
| Признак в сообщении | Что это значит | Починка |
|---|---|---|
Есть хвост Did you mean 'X'? |
Опечатка в имени параметра | Подставить имя из подсказки |
| Хвоста нет, Python 3.13 и выше | Похожего параметра в сигнатуре нет | Сверить inspect.signature и версию пакета |
positional-only arguments passed as keyword |
Параметры стоят до / |
Передать позиционно, без имени |
| Имя функции в ошибке другое | Аргументы принял вложенный вызов или родительский класс | Искать определение по имени из ошибки |
| Ошибка появилась после обновления | Сигнатура библиотеки изменилась | pip show плюс changelog версии |
| Аргументы приходят из JSON или формы | В словаре лишние ключи | Фильтр словаря по signature().parameters |
SyntaxError вместо TypeError |
Слева от «равно» стоит выражение | Простое имя параметра или распаковка словаря |
Две операции из таблицы стоит освоить первыми: проверка имен по сигнатуре и изменение определения функции под фактический вызов. Примеры обеих — в разделах «Как исправить ошибку unexpected argument» и «Декоратор, который возвращает контроль имен», с дословным выводом интерпретатора.
Первая проверка перед долгим разбором — python -V. Подсказка «Did you mean» для ключевых аргументов появилась в 3.13, поэтому её отсутствие на 3.12 и на 3.13 значит разные вещи, и одна эта строка задаёт всю дальнейшую ветку разбора.
Частые вопросы про unexpected argument
Что означает ошибка TypeError: got an unexpected keyword argument?
Что имя, переданное при вызове, отсутствует в сигнатуре функции. Python сопоставляет ключевые аргументы с параметрами определения по именам и прерывает вызов до входа в тело функции.
С какой версии Python сам подсказывает правильное имя аргумента?
С версии 3.13. Интерпретатор добавляет к сообщению хвост вида Did you mean ‘name’?, если в сигнатуре есть похожее имя. На 3.12 и ниже такого хвоста нет, и сигнатуру приходится смотреть руками.
Почему имя функции в тексте ошибки отличается от того, которое я вызывал?
Потому что имя в сообщении принадлежит тому объекту, который реально принимал аргументы. Вызов sorted отвечает от имени sort, а конструктор наследника с **kw передаёт проблему в Base.__init__ родительского класса.
Как передать словарь в функцию, чтобы лишние ключи не ломали вызов?
Отфильтровать словарь по сигнатуре перед распаковкой: allowed = set(inspect.signature(func).parameters), затем передать только пары, чьи ключи входят в allowed. Вариант с **kwargs тоже работает, но он прячет опечатки в именах.
Чем SyntaxError отличается от TypeError про unexpected argument?
Моментом срабатывания. Сообщения expression cannot contain assignment и keyword argument repeated выдаёт парсер до запуска программы, поэтому не выполнится ни одна строка файла. TypeError про unexpected argument возникает во время работы, когда предыдущие строки уже отработали.
