Декоратор на Python
Задача: реализовать декоратор @contract. Смотри файл contract.py
Требования:
Необходимо проверять типы аргументов и тип выходного значения функции. Указываем кортеж типов для
arg_types. Каждый тип в кортеже - соответсвует типу аргумента. Для типа выходного значения - указываемreturn_type@contract(arg_types=(int, int), return_type=int) def add_two_numbers(first, second): return first + second add_two_numbers(1, 2) # okЕсли передан неправильный тип, вызываем ошибку
ContractError:add_two_numbers('a', 'b') # raises ContractErrorМожно не передавать какое-то значение из
arg_typesилиreturn_type. Или передать значениеNone: тогда ничего не будет происходить. Пример:@contract(return_type=int) # validates only return type, args are ignored @contract(return_type=None, arg_types=None) # validation is disabled @contract(arg_types=(str, str)) # return type check is disabledМожно передать специальное значение
Anyдля того, чтобы игнорировать какой-то один тип внутриarg_types. Например:@contract(arg_types=(int, Any)) def add_two_numbers(first, second): return first + second add_two_numbers(1, 2) # ok add_two_numbers(1, 3.4) # ok add_two_numbers(2.1, 1) # raises ContractErrorПараметр
raisesотвечает за типы исключений, которые функция может кидать. Если выкинутое исключение отсутсвует в списке разрешенных, то мы добавляемContractError(смотриraise from). Пример:@contract(arg_types=(int, int), return_type=float, raises=(ZeroDivisionError,)) def div(first, second): return first / second div(1, 2) # ok div(1, 0) # raises ZeroDisionError div(1, None) # raises ContractError from TypeError
Файл contract.py
class ContractError(Exception):
"""We use this error when someone breaks our contract."""
#: Special value, that indicates that validation for this type is not required.
Any = object()
def contract(arg_types=None, return_type=None):
... # TODO: implement
Я пробовал сделать первый пункт задачи данным путем, но я даже его не смог пробить, что говорить о следующих пунктах.. Помогите пожалуйста реализовать данную задачу, я не понимаю что необходимо сделать тут, примеров в интернете не могу найти вот и обращаюсь на прямую к специалистам :(((
Я только учусь, всю голову себе сломал этой задачей
class ContractError(Exception):
"""We use this error when someone breaks our contract."""
#: Special value, that indicates that validation for this type is not required.
Any = object()
def contract(arg_types=None, return_type=None):
def inner(function, *args, **kwargs):
print('Args', args, kwargs)
result = function(*args, **kwargs)
print('Result',result)
return result
return inner
@contract(arg_types=(int, int), return_type=int)
def add_two_numbers(first, second):
print(type(first),type(second))
return first + second
add_two_numbers(1, 2) # ok
Ответы (1 шт):
Может быть примерно так. Для первого пункта. И дальше по аналогии.
def contract(arg_types, return_type):
def actual_decorator(func):
def wrapper(*args, **kwargs):
for idx, exp_type in enumerate(arg_types):
if (exp_type != type(args[idx])):
raise AttributeError("Must be int")
if (type(func(*args, **kwargs)) != return_type):
raise AttributeError("Must be int")
return 'ok'
return wrapper
return actual_decorator
@contract(arg_types=(int, int), return_type=int)
def add(a, b):
return a + b
print(add(2, 2.5)) # Exception
print(add(2, 2)) #ok