发布于 2013-03-08 17:49:24
来自函数和方法的装饰器
Python 2
def accepts(*types):
def check_accepts(f):
assert len(types) == f.func_code.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a,t)
return f(*args, **kwds)
new_f.func_name = f.func_name
return new_f
return check_acceptsPython 3
在Python3中,func_code已改为__code__,func_name已更改为__name__。
def accepts(*types):
def check_accepts(f):
assert len(types) == f.__code__.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a,t)
return f(*args, **kwds)
new_f.__name__ = f.__name__
return new_f
return check_accepts用法:
@accepts(int, (int,float))
def func(arg1, arg2):
return arg1 * arg2
func(3, 2) # -> 6
func('3', 2) # -> AssertionError: arg '3' does not match <type 'int'>arg2可以是int,也可以是float
发布于 2013-03-08 17:32:41
在Python3.3上,您可以使用函数注释并检查:
import inspect
def validate(f):
def wrapper(*args):
fname = f.__name__
fsig = inspect.signature(f)
vars = ', '.join('{}={}'.format(*pair) for pair in zip(fsig.parameters, args))
params={k:v for k,v in zip(fsig.parameters, args)}
print('wrapped call to {}({})'.format(fname, params))
for k, v in fsig.parameters.items():
p=params[k]
msg='call to {}({}): {} failed {})'.format(fname, vars, k, v.annotation.__name__)
assert v.annotation(params[k]), msg
ret = f(*args)
print(' returning {} with annotation: "{}"'.format(ret, fsig.return_annotation))
return ret
return wrapper
@validate
def xXy(x: lambda _x: 10<_x<100, y: lambda _y: isinstance(_y,float)) -> ('x times y','in X and Y units'):
return x*y
xy = xXy(10,3)
print(xy)如果存在验证错误,请打印:
AssertionError: call to xXy(x=12, y=3): y failed <lambda>)如果没有验证错误,请打印:
wrapped call to xXy({'y': 3.0, 'x': 12})
returning 36.0 with annotation: "('x times y', 'in X and Y units')"您可以使用函数而不是lambda来获得断言失败中的名称。
发布于 2016-02-29 14:58:24
正如你所知道的,仅仅根据一个论点的类型来拒绝它并不是节奏曲。
Pythonic的方法更像是“先处理它”。
这就是为什么我宁愿做一个装潢师来转换论点
def enforce(*types):
def decorator(f):
def new_f(*args, **kwds):
#we need to convert args into something mutable
newargs = []
for (a, t) in zip(args, types):
newargs.append( t(a)) #feel free to have more elaborated convertion
return f(*newargs, **kwds)
return new_f
return decorator这样,您的函数就会得到您所期望的类型,但是如果参数可以像浮点一样嘎嘎地运行,则它将被接受。
@enforce(int, float)
def func(arg1, arg2):
return arg1 * arg2
print (func(3, 2)) # -> 6.0
print (func('3', 2)) # -> 6.0
print (func('three', 2)) # -> ValueError: invalid literal for int() with base 10: 'three'我使用这个技巧(使用适当的转换方法)来处理向量。
我编写的许多方法都期望使用MyVector类,因为它具有大量的功能;但是有时您只想编写
transpose ((2,4))https://stackoverflow.com/questions/15299878
复制相似问题