我想要一个易于使用的装饰器类,可用于强制某些参数为预定义类型,以免引发错误。问题是我必须指定每个变量两次,每个args一个,kwargs一个。即使使用默认参数也是如此,前提是原始函数中没有单个splat参数。
简化为:
class ParamConstraint:
def __init__(self, *args, error=TypeError, **kwargs):
self.args = args
self.kwargs = kwargs
self.error = error
def __call__(self, function):
def wrap(*args, **kwargs):
for (arg, constraint) in zip(args, self.args):
if not isinstance(arg, constraint):
raise self.error(
"Value '{}' is not of type '{}'.".format(arg, constraint.__name__)
)
for kwarg in self.kwargs:
if kwarg in kwargs:
assert isinstance(kwargs[kwarg], self.kwargs[kwarg])
return function(*args, **kwargs)
return __import__("functools").wraps(function)(wrap)
这很容易使用。假设我想要一个将数字乘以2的函数,但我只想要整数,而不是浮点数。我可以用:
@ParamConstraint(int)
def foo(x):
return x*2
print(foo(5)) # => prints 10
print(foo(x=5.0)) # => prints 10.0
print(foo(5.0)) # => raises TypeError
现在,我可以通过将位置和非位置参数传递到函数中来防止这种情况,但一段时间后它变得非常乏味。例如,我必须为3个参数写出6个约束:
@ParamConstraint((int, float), int, FunctionType, value=(int, float), count=int, func=FunctionType):
def foo(value, count, func):
for _ in range(count):
value = func(value)
return value
理想情况下,我应该能够通过KWarg传递它而不提供任何位置参数。但是,这不起作用,因为我无法找出原始函数的位置参数是什么。我曾使用inspect
模块无效。
我该如何补救?