我构建了一个类型检查装饰器(带包装):
def accepts_func(*types):
"""
top-level decoration, consumes parameters
"""
def decorator(func):
"""
actual decorator function, consumes the input function
"""
@wraps(func)
def check_accepts(*args):
"""
actual wrapper which does some magic type-checking
"""
# check if length of args matches length of specified types
assert len(args) == len(types), "{} arguments were passed to func '{}', but only {} " \
"types were passed to decorator '@accepts_func'" \
.format(len(args), func.__name__, len(types))
# check types of arguments
for i, arg, typecheck in izip(range(1, len(args)+1), args, types):
assert isinstance(arg, typecheck), "type checking: argument #{} was expected to be '{}' but is '{}'" \
.format(i, typecheck, type(arg))
return func(*args)
return check_accepts
return decorator
您可以传递任意数量的类型,它会检查传递给
func
的参数类型是否与 @accepts_func(param_type1, param_type2, ...)
中“硬编码”的类型匹配:
@accepts_func(int, str)
sample_func(arg1, arg2):
...does something...
到目前为止,没有任何问题。
但是,由于我不是Python“大师”,我想知道我的解决方案是否适合“更大”的项目?
我的解决方案有什么缺点吗? 例如。比如性能问题、边缘情况下未捕获的错误等等?
有办法改进我的解决方案吗?是否存在更好、更“Pythonic”的解决方案?
注意:我不会对项目中的每个函数进行类型检查,只是对我认为真正需要类型安全的函数进行类型检查。该项目在服务器上运行,因此抛出的错误出现在日志中并且对用户不可见。
我实际上不鼓励对输入变量进行类型检查。抛开性能不谈,Python 是一种动态类型语言,在某些情况下(例如测试),您需要传递一个对象来实现您最初计划使用的对象的某些属性,这将与您的代码配合良好。
一个简单的例子:
class fake_str:
def __init__(self, string):
self.string = string
def __str__(self):
return self.string
string = fake_str('test')
isinstance(string, str) # False
string # 'test'
你为什么不接受有效的东西?
只需允许兼容的对象与您的代码一起工作。
我正在寻找一个类型检查装饰器,但找不到任何在现代维护的东西。该线程出现在搜索结果的顶部。在尝试使用此处的代码实现我自己的类型检查装饰器但失败后,我最终偶然发现了typeguard。
如果您想要类型检查,请使用 python 3.5 及其支持内置类型提示的类型模块。
http://blog.jetbrains.com/pycharm/2015/11/python-3-5-type-hinting-in-pycharm-5/
编辑:
作为对读者的警告。像 python 这样的语言中的类型提示可能很有用,但也很痛苦。许多 python API 都是高度多态的,接受许多不同类型的不同参数和可选参数。这些函数的类型签名是gnarly并且注释它们根本没有帮助。但对于接受和返回简单类型的简单函数,类型提示只能帮助提高清晰度。