Проблема здесь:
if type(val) == str:
try:
val = int(val)
except ValueError:
return f'First argument must be a number (tried {val})'
Когда вы передаете 'foo'
, он (правильно) определяется как str
и пытается преобразовать его в int
. Но 'foo'
не может быть проанализирован как int
, поэтому он возвращает сообщение об ошибке.
Декораторы просто syntacti c sugar:
@val_limiter('foo')
def test(val)
return val
примерно эквивалентно :
def test(val)
return val
test = val_limiter('foo')(test)
Таким образом, для случая 'foo'
эта последняя эквивалентная строка становится такой:
test = 'First argument must be a number (tried foo)'(test)
, которая пытается "вызвать" str
, как если бы это была функция .
Главный вывод из этого заключается в том, что вы не должны ловить исключения, когда вы не можете сделать с ними ничего полезного. Многие вводные курсы по программированию учат , как ловить исключения, но не , когда делает это (на самом деле, упражнения, которые учат вас, как это делать, часто делают это неправильно, преобразовывая исключения в print
или return
s, которые не имеют смысла, если только вызывающая сторона явно не проверяет возвращаемые типы и значения, то есть то, что исключения должны избегать ).
В этом В этом случае вам может потребоваться более полезное сообщение об ошибке, поэтому перехватывать его можно , если вы вызываете новое исключение с более приятным сообщением об ошибке (вы делаете более дружелюбное сообщение, но по-прежнему существует ошибка, которую вы не видите не имеет контекста для обработки), вместо того, чтобы молча возвращать мусор (возвращая что-либо, но функция здесь возвращает мусор). Таким образом, в этом случае вы можете изменить:
return f'First argument must be a number (tried {val})'
на:
raise ValueError(f'First argument must be a number (tried {val!r})')
, что вызывает исключение, которое не может случайно использоваться как функция (способ без ошибок возврат будет использоваться).