2011-01-19 103 views
1

我不确定我的问题有一个具体的答案,但无论如何。我正在编写一个有很多参数的函数,每个函数都可以是None或者有一个有限的值范围。由于我不相信用户给我很好的输入,我必须检查每个参数的类型,如果它的类型正确(或None),那么我想看看它是否在正确的范围内。这意味着我有这样大量的代码:Python中的逻辑参数检查

# size 
if isinstance(size, str): 
    if size in range(4): 
     self.data[uid]['size'] = int(size) 
    else: 
     warnings.warn("ID %s: illegal size %s" % (uid, size)) 
     self.data[uid]['size'] = None 
elif size == None:         
    self.data[uid]['size'] = None 
else: 
    warnings.warn("ID %s: illegal size %s" % (uid, str(size))) 
    self.data[uid]['size'] = None 

等。这是成为重复的,我想知道是否有可能是会自动执行此,抛出异常/警告,并减少代码冗余库。

感谢

+6

`我必须检查每个参数的类型`听起来像你做错了。你应该只用它作为预期的类型,然后捕捉失败。 – Falmarri 2011-01-19 22:03:21

+3

我曾经认为我也必须检查输入。当我停止这样做时,编程变得更加容易。假设没关系,并处理错误。这与python成语“容易要求宽恕而不是权限”有关。 – Wilduck 2011-01-19 22:07:46

回答

1

我想知道是否有可能是一个 库会自动执行此, 抛出异常/警告,并减少 代码冗余。

我使用formencode这样的东西。它似乎只用于解析HTML表单,但它会高兴地解析和验证您传递给它的任何内容。您可以定义一次验证所有输入的模式类。

0

如果你的项目是一个库,你的“用户”是另一家开发商,不这样做的。顶多有一个断言替换你的测试:

assert 0 <= int(size) <= 4, "size must be between 0 and 4" 

这样,当用户提供错误的输入,他们会听到它马上 - 那么它变成自己的责任得到它的权利。


如果你的项目是一个应用程序,你的“用户”是我奶奶,你需要做自己的验证:撞车出局不是一个可接受的响应。但是,在这种情况下,您应该更多地了解可能的输入(例如,它来自文本框,因此它只能是一个字符串)。

我的建议是编码你的效用函数,并单独执行验证(即UI层)。一个实用程序/库函数应该验证并覆盖(甚至是警告)这个值是非常罕见的:它需要阻止调用者/用户进一步得到它,直到他们已经把事情做好了。

1

我同意上面的说法:假设size是正确的类型,如果不是,则引发异常(或返回错误)。

虽然在处理可能引发异常的输入时存在一个有用的模式:包装输入引发的任何异常,使其包含输入。例如,所以你会得到:

 
ParseError: while parsing 'number = foo': ValueError: invalid literal for int() with base 10: 'foo' 

的代码看起来是这样的:

try: 
    parse(input) 
catch Exception, e: 
    raise ParseError("while parsing %r: %r" %(input, e)), None, sys.exc_info()[2] 

的第三个参数raise将使用原来的追踪,所以堆栈跟踪将指向你的实际上导致错误的行(例如,size = int(value))而不是对raise的调用。

1

我想改写这个:

# size 
if isinstance(size, str): 
    if size in range(4): 
     self.data[uid]['size'] = int(size) 
    else: 
     warnings.warn("ID %s: illegal size %s" % (uid, size)) 
     self.data[uid]['size'] = None 
elif size == None:         
    self.data[uid]['size'] = None 
else: 
    warnings.warn("ID %s: illegal size %s" % (uid, str(size))) 
    self.data[uid]['size'] = None 

这样的:

if size in ["0", "1", "2", "3"]: # alternative: if size in map(str, range(4)): 
    self.data[uid]['size'] = int(size) 
else: 
    if size != None: 
     warnings.warn("ID %s: illegal size %s" % (uid, size)) 
    self.data[uid]['size'] = None  

我真诚地不喜欢的是使用isinstance(size, str)(显式类型检查一般是在Python中,因为它很容易地皱起了眉头打破ducktyping)。

这就是为什么你不容易在Python中找到一个库来自动化类型检测的原因:它违背了语言的核心意图。