Почему TypeError, когда слишком много / слишком мало аргументов в вызове функции Python - PullRequest
4 голосов
/ 31 мая 2011

Мне трудно понять, почему Python вызывает TypeError, когда вы предоставляете аргументы, которые не являются частью сигнатуры метода.

Пример:

>>> def funky():
...    pass
... 
>>> funky(500)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: funky() takes no arguments (1 given)

Я подумал, если это потому, что *args, как ожидается, будет None или [] в рамках функции без аргументов, это негерметичная абстракция , поэтому я посмотрел ее .

Что я нашел

Поиск страницы для TypeError на PEP-3102 нашел то, что казалось оправданием для одного контекста, в котором поднялся TypeError, но я не понимаю оправдания. Пример PEP по существу утверждает, что функциональность - это, по сути, ярлык для if args: raise TypeError(). args - это непустой список в этом случае, в отличие от пустого списка ... оба они одного типа. Если я не ошибаюсь и что является действительно оправданием, возможно, ValueError будет более подходящим. Тем не менее, это все равно будет своего рода утечка абстракции, поскольку пример написан на Python, что делает его скорее деталями реализации определенного варианта использования, чем языковой особенностью. Что-то вроде ArgumentError звучит здесь гораздо более уместно для меня, и это заставляет меня поверить, что есть некое очевидное объяснение, которое я пропустил, почему TypeError имеет смысл.

Ответы [ 2 ]

0 голосов
/ 24 февраля 2014

Вы сказали: def funky (): ... Так что программа "funky" не должна принимать никаких "аргументов".Но когда вы использовали программу, вы сказали, что funky (аргумент), и funky не принимает аргументы, так что это вызвало ошибку.Чтобы это исправить, используйте;def funky (n): pass.

0 голосов
/ 31 мая 2011

Функция принимает n аргументы. Вы предоставили m. n != m. Вероятно, это ошибка в чьем-то коде или признак непонимания чьего-то API. Кроме того, я не думаю, что мы могли бы договориться о значимой, полезной семантике, что должно произойти в этом случае. Следует ли игнорировать лишние аргументы? Это позволило бы таким ошибкам пройти, и, поскольку «ошибки никогда не пройдут молча», это неприемлемо. Аналогичным образом, предоставление некоторого значения по умолчанию для пропущенных аргументов допускает тихое неправильное поведение в случае опечаток и т. Д. И, таким образом, нарушает тот же принцип, не говоря уже о том, что «явный лучше, чем неявный», т. Е. Если вы хотите передать какое-то специальное значение, вы должны просто запиши это.

PEP, на который вы ссылаетесь, и его if args: raise TypeError(...) семантика применяются только к функциям с аргументами только для ключевых слов, которые не принимают varargs и используют простой * в списке параметров для кодификации этого. Есть функции, которые принимают ограниченное количество позиционных аргументов и выиграют от аргументов только для ключевых слов, но varargs не будет для них значимым. Для них существует простой *, позволяющий разрешать аргументы только для ключевых слов, не требуя шаблонного кода, и при этом уведомлять программиста в случае, если кто-то предоставляет слишком много аргументов (что хорошо по причинам, перечисленным в первой части ответа).

Что и почему было выбрано TypeError: «Неверное количество аргументов» - это ошибка типа компиляции / несоответствие типа в статических языках. У нас нет проверки во время компиляции для таких вещей в Python, но это все еще своего рода «ошибка типа». Если (в Python, неофициальный) тип подписи говорит: «Я беру два аргумента», а вы предоставляете три, это, очевидно, является нарушением этого контракта. TypeError не просто означает not isinstance(x, expected), как и многие другие темы, связанные с типизацией (просто подумайте о наследовании и "получает родительский материал" против "is-a parent"), это гораздо более широкое понятие.

Отредактируйте в ответ на вашу критику сравнения статической типизации: рассмотрение унарной функции, отличной от бинарной функции, - не просто ограничение системы статического типа. Это очень полезно даже в таких языках, как Python, поскольку они не настолько похожи, чтобы их можно было использовать «как если бы они ходили и крякали одинаково» (как при наборе утки) - их нельзя использовать одинаково. (Исключение, метапрограммирование, которое оборачивает функции абриритичности, обрабатывается операторами распаковки * и **.) Они случайно разделяют тот факт, что их можно вызывать, но они несовместимы, даже если встроенная объектная иерархия Python не создает многочисленные идентичные классы, которые отличаются только арностью и, следовательно, именем. type(f) может сказать function, но это не всегда конец истории.

...