1def type_check(check_type): #it takes only a function as arg
2 def decorator_func(*allowed_types): #we divide in 2 cases here and create separate decorators based on the check type
3 if check_type == "in":
4 def validate_input(func): #create decorator for input & output separately
5 def wrapper(*args, **kwargs): #wrapper of the first decorator
6 invalid_input = False
7 for arg in args:
8 if not type(arg) in allowed_types:
9 invalid_input = True
10 break
11 if invalid_input:
12 print(f"Invalid input arguments, expected {', '.join(map(str, allowed_types))}!") #tozi fstring go otkradnah :)
13
14 return func(*args, **kwargs) #if its invalid, we will have an error, but it will print a message before the error occurs
15
16 return wrapper
17
18 return validate_input
19 else: #we need to check the output
20 def validate_output(func):
21 def wrapper(*args, **kwargs):
22 result = func(*args, **kwargs) #we call the function and unwrap the arguments
23
24 if not type(result) in allowed_types:
25 print(f"Invalid output value, expected {', '.join(map(str, allowed_types))}!")
26#if the output is invalid, we will get an error when calling func and we will print the messange later
27 return result
28
29 return wrapper
30
31 return validate_output
32
33 return decorator_func
34
35
36"""@type_check("in")(int, float)
37@type_check("out")(int, float)
38def power(num, pow):
39 return num ** pow
40
41print(power(6j, 2))"""
42
43"""@type_check("in")(str)
44def concatenate(*strings, separator=' beep boop '):
45 return separator.join(strings)
46
47print(concatenate(5, '6'))"""
....
----------------------------------------------------------------------
Ran 4 tests in 0.002s
OK