Подскажите как скорректировать декоратор python
Есть такая задача:
Напишите декоратор @takes, который будет проверять правильность типов входных аргументов функции, которая принимает лишь позиционные аргументы.
Декоратор принимает на вход типы аргументов и декорирует функцию таким образом, что если хотя бы один из аргументов имеет неверный тип, то декорированная функция не исполняется и выводится сообщение "ERROR!".
Если количество аргументов функции и количество переданных типов разное:
аргументов больше, чем типов - ошибку генерировать не нужно (возможно, точные типы данных известны только для первых аргументов, их как раз и надо проверить)
типов больше, чем аргументов - ошибка, если переданные аргументы не подходят под соответствующие им по порядку типы (декоратор может быть применен к функциям с переменным числом аргументов).
Декоратор должен вести себя порядочно, то есть не должен затирать основные аргументы функции (__name__, __doc__, __module__).
у меня вообще капитальная беда с декораторами, поэтому все до чего удалось дойти пока выглядит так:
import inspect
# decorator
def takes(func):
def inner(*args,**kwargs):
for i in args, kwargs:
if i.kind != i.POSITIONAL_ONLY:
print('ERROR!')
else:
func(*args,**kwargs)
return inner
@takes
def f(1, '1'):
print('OKAY')
Выдает ошибку:
File "/var/folders/pd/y35txfqs6wz0h0q_6kbx9y040000gn/T/ipykernel_6267/3786218546.py", line 15
def f(1, '1'):
^
SyntaxError: invalid syntax
Не понимаю, что конкретно не так, помогите, пожалуйста.
Вот такой код после комментария
# decorator
def takes(func):
def inner(*args,**kwargs):
if kwargs:
print('ERROR!')
func(*args,**kwargs)
return inner
@takes
def fun(*args,**kwargs):
print('OKAY')
fun(1, '1')
Теперь ошибка исчезла , но ответ некорректный. При попытке fun(1,1) тоже выйдет OKAY, хотя должно быть ERROR!
Ответы (1 шт):
import functools
def type_dec(*type_args):
type_args_len = len(type_args)
def dec(func):
@functools.wraps(func)
def wrap(*args, **kwargs):
assert len(args) >= type_args_len, f'типов({type_args_len} шт.) больше, чем аргументов({len(args)} шт.)'
for t, a in zip(type_args, args):
if type(a) != t:
raise TypeError(f"ERROR! аргумент `{a}` имеет неверный тип {type(a).__name__}, а должен быть {t.__name__}")
return func(*args, **kwargs)
return wrap
return dec
@type_dec(int, str)
def get_result_1(a, b, c):
"""test"""
return 'ok'
@type_dec(str, str, str)
def get_result_2(a):
return 'ok'
if __name__ == '__main__':
# >>> get_result test __main__
print(get_result_1.__name__, get_result_1.__doc__, get_result_1.__module__, )
# >>> 'ok'
print(get_result_1(1, '2', 3))
# >>> TypeError: ERROR! аргумент `2` имеет неверный тип int, а должен быть str
print(get_result_1(1, 2, 3))
# >>> AssertionError: типов(3 шт.) больше, чем аргументов(1 шт.)
print(get_result_2(1))