python中实现参数类型检查的简单方法

python是一门弱类型语言,很多从c/c++转过来的朋友起初不是很适应。比如,在声明一个函数时,不能指定参数的类型。用c做类比,那就是所有参数都是void*类型!void类型强制转换在c++中被广泛地认为是个坏习惯,不到万不得已是不会使用的。

python自然没有类型强制转换一说了,因为它是动态语言。首先,所有对象都从object继承而来,其次,它有强大的内省,如果调用某个不存在的方法会有异常抛出。大多数情况,我们都不需要做参数类型栓查,除了一些特殊情况。例如,某个函数接受一个str类型,结果在实际调用时传入的是unicode,测试过程中又没有代码覆盖到,这样问题就比较严重了。解决方法也很简单,借助python的内省,很容易就能判断出参数的类型。但是每个地方都写检查代码会很累赘,何况它带来的实际价值并不高。一个好的解决方法是使用装饰器。

”’
>>> none, medium, strong = 0, 1, 2
>>>
>>> @accepts(int, int, int)
… def average(x, y, z):
… return (x + y + z) / 2

>>> average(5.5, 10, 15.0)
typewarning: ‘average’ method accepts (int, int, int), but was given
(float, int, float)
15.25
”’
def accepts(*types, **kw):
“”” function decorator. checks that inputs given to decorated function
are of the expected type.
parameters:
types — the expected types of the inputs to the decorated function.
must specify type for each parameter.
kw — optional specification of ‘debug’ level (this is the only valid
keyword argument, no other should be given).
debug = ( 0 | 1 | 2 )
“””
if not kw:
# default level: medium
debug = 1
else:
debug = kw[‘debug’]
try:
def decorator(f):
def newf(*args):
if debug == 0:
return f(*args)
assert len(args) == len(types)
argtypes = tuple(map(type, args))
if argtypes != types:
msg = info(f.__name__, types, argtypes, 0)
if debug == 1:
print >> sys.stderr, ‘typewarning: ‘, msg
elif debug == 2:
raise typeerror, msg
return f(*args)
newf.__name__ = f.__name__
return newf
return decorator
except keyerror, key:
raise keyerror, key + “is not a valid keyword argument”
except typeerror, msg:
raise typeerror, msg
def info(fname, expected, actual, flag):
“”” convenience function returns nicely formatted error/warning msg. “””
format = lambda types: ‘, ‘.join([str(t).split(“‘”)[1] for t in types])
expected, actual = format(expected), format(actual)
msg = “‘%s’ method ” % fname \
+ (“accepts”, “returns”)[flag] + ” (%s), but ” % expected\
+ (“was given”, “result is”)[flag] + ” (%s)” % actual
return msg

本质上讲,这也是一种运行时检查,但效果已经不错了。
更多有趣的装饰器的使用,可以参考这篇文章http://wiki.python.org/moin/pythondecoratorlibrary

Posted in 未分类