patternpythonMinor
Strict types decorator (works only with Python 3.5)
Viewed 0 times
withworkspythontypesdecoratorstrictonly
Problem
I wrote a decorator which makes Python 3.5 raise exceptions if the arguments that are passed to a type-hinted function are of the wrong type.
It's used like this:
and if something of the wrong type is passed to the decorated function e.g.
The part that I'm worried about is the part that checks the result. It calls the original function (to learn result of what type it returns), but returns a wrapped function
from typing import get_type_hints
def strict_types(f):
def type_checker(*args, **kwargs):
hints = get_type_hints(f)
all_args = kwargs.copy()
all_args.update(dict(zip(f.__code__.co_varnames, args)))
for key in all_args:
if key in hints:
if type(all_args[key]) != hints[key]:
raise Exception('Type of {} is {} and not {}'.format(key, type(all_args[key]), hints[key]))
res = f(*args, **kwargs)
if type(res) == hints['return']:
return res
else:
raise Exception('Type of result is {} and not {}'.format(type(res), hints['return']))
return type_checkerIt's used like this:
@strict_types
def concatenate_with_spam(text: str) -> str:
return text + 'spam'and if something of the wrong type is passed to the decorated function e.g.
concatenate_with_spam(42) an exception is raised:Exception: Type of text is and not The part that I'm worried about is the part that checks the result. It calls the original function (to learn result of what type it returns), but returns a wrapped function
type_checker that will be called one more time, so the runtime of function is (at least) multiplied by 2. Are there any other things I have missed? What can be improved here (except for not using this not-pythonic decorator and crucifying me for writing it)?Solution
You should change this part a bit:
Here, you are silently ignoring missing type hints, but if the user went as far as to use this decorator, you should raise an exception instead, like this:
Specific Errors & Exceptions
Order of conditionals
Here, the real logic is in the
Now it looks more like a simple perturbation of an almost linear function, than a full-blown logic statement.
Please do not abbreviate
It takes 0.5 seconds more to type and a tenth of the time to read.
for key in all_args:
if key in hints:
if type(all_args[key]) != hints[key]:
raise Exception('Type of {} is {} and not {}'.format(key, type(all_args[key]), hints[key]))Here, you are silently ignoring missing type hints, but if the user went as far as to use this decorator, you should raise an exception instead, like this:
for key in all_args:
try:
if type(all_args[key]) != hints[key]:
raise Exception('Type of {} is {} and not {}'.format(key, type(all_args[key]), hints[key]))
except IndexError:
raise TypeError('The formal parameter {} was not given a type'.format(key))Specific Errors & Exceptions
Exception is hilariously un-informative, use TypeError to convey more information.Order of conditionals
if type(res) == hints['return']:
return res
else:
raise Exception('Type of result is {} and not {}'.format(type(res), hints['return']))Here, the real logic is in the
else, but I prefer seeing the main logic after the if, like this:if type(res) != hints['return']:
raise Exception('Type of result is {} and not {}'.format(type(res), hints['return']))
return resNow it looks more like a simple perturbation of an almost linear function, than a full-blown logic statement.
Please do not abbreviate
res -> result
func -> function
It takes 0.5 seconds more to type and a tenth of the time to read.
Code Snippets
for key in all_args:
if key in hints:
if type(all_args[key]) != hints[key]:
raise Exception('Type of {} is {} and not {}'.format(key, type(all_args[key]), hints[key]))for key in all_args:
try:
if type(all_args[key]) != hints[key]:
raise Exception('Type of {} is {} and not {}'.format(key, type(all_args[key]), hints[key]))
except IndexError:
raise TypeError('The formal parameter {} was not given a type'.format(key))if type(res) == hints['return']:
return res
else:
raise Exception('Type of result is {} and not {}'.format(type(res), hints['return']))if type(res) != hints['return']:
raise Exception('Type of result is {} and not {}'.format(type(res), hints['return']))
return resContext
StackExchange Code Review Q#105758, answer score: 3
Revisions (0)
No revisions yet.