我正在尝试对我的python代码执行良好的输入有效性检查,但我也希望它简洁明了。也就是说,我不想要的解决方案就是这个:
def some_func(int_arg, str_arg, other_arg):
try:
int_arg = int(int_arg)
except TypeError, ValueError
logging.error("int_arg must respond to int()")
raise TypeError
try:
if str_arg is not None:
str_arg = str(str_arg)
except TypeError
logging.error("Okay, I'm pretty sure this isn't possible, bad example")
raise TypeError
if other_arg not in (VALUE1, VALUE2, VALUE3):
logging.error("other arg must be VALUE1, VALUE2, or VALUE3")
raise TypeError
这只是太多的代码和太多的空间,只需要检查3个参数。
我目前的做法是:
def some_func(int_arg, str_arg, other_arg):
try:
int_arg = int(int_arg) #int_arg must be an integer
str_arg is None or str_arg = str(str_arg) #str_arg is optional, but must be a string if provided
assert other_arg in (VALUE1, VALUE2, VALUE3)
catch TypeError, ValueError, AssertionError:
logging.error("Bad arguments given to some_func")
throw TypeError
我失去了我的日志消息的特异性,但在我看来,这更简洁,更诚实。
我特别想知道的是使用assert语句。我已经读过,不鼓励使用断言作为检查输入有效性的方法,但我想知道这是否是一种合法的使用方法。
如果没有,是否有类似的方法来执行此检查(或通常进行此验证)仍然非常简洁?
答案 0 :(得分:8)
你可以发明一个装饰器,为你验证参数。
这就是语法的样子:
@validate(0, int)
@validate(1, str, logMessage='second argument must respond to str()')
@validate(2, customValidationFunction)
def some_func(int_arg, str_arg, other_arg):
# the control gets here only after args are validated correctly
return int_arg * str_arg
这是验证装饰工厂的一个简单实现。
def validate(narg, conv, logMessage = None):
def decorate(func):
def funcDecorated(*args):
newArgs = list(args)
try:
newArgs[narg] = conv(newArgs[narg])
except Exception, e:
# wrong argument! do some logging here and re-raise
raise Exception("Invalid argument #{}: {}".format(narg, e))
else:
return func(*newArgs)
return funcDecorated
return decorate
是的,这里有一些函数嵌套,但这一切都有意义。让我解释一下:
validate(narg, converter)
是一个需要进行一些设置并返回特定装饰器(decorate
)的函数,该装饰器根据这些设置运行decorate
来装饰给定函数(func
),该函数通过创建一个与funcDecorated
采用相同参数的新函数func
来获取一些位置参数( *args
)并根据输入函数func
以及初始设置narg
,conv
编写。实际验证发生在funcDecorated中,其中......
conv
做什么),func
。为了对多个参数执行此操作,我们使用不同的参数多次应用validate
。 (有可能将其重写为仅装饰一次,但IMO的方式看起来更清晰。)
查看实际操作:http://ideone.com/vjgIS
请注意conv
可以采取行动......
请注意,此实现不处理关键字参数。
答案 1 :(得分:1)
使用断言完全可以检查参数的有效性(类型,类或值,这正是您正在检查的内容)。
你说:
我特别想知道的一件事是使用断言 言。
所以我认为this page对您有用。
特别是这部分:
断言应该不用于测试由于用户输入错误或操作系统/环境失败而导致的故障情况,例如找不到文件。
答案 2 :(得分:0)
您可以查看contracts库。 它允许您声明函数参数的约束(甚至它的返回值)。
答案 3 :(得分:0)
@Vicent提供了great page的链接(可能在此期间进行了编辑)。 如果您需要检查,建议按以下方式键入检查
from types import IntType, StringType
def some_func(int_arg, str_arg, other_arg):
assert type(int_arg) == IntType, "id is not an integer: %r" % int_arg
assert type(str_arg) == StringType or not str_arg
assert other_arg in (VALUE1, VALUE2, VALUE3), "other arg must be VALUE1, VALUE2, or VALUE3"
断言的好处在于它显示了失败的代码行。