我想知道我正在做的是一种适当的断言方法。我正在尝试为Python的样式指南制作简洁且非常正确的内容。
try:
assert self.port_number == 0
assert self.handle == None
assert isinstance(port_number, int) or isinstance(port_number, float)
assert port_number > 0
except AssertionError:
return -1
*body of code*
return 0
上面是我的代码的摘录,显示了我如何处理参数断言。你可以假设我已经涵盖了所有必要的断言,输入是port_number。这被认为是好风格吗?还有更好的方法吗?
答案 0 :(得分:5)
assert
语句只应用于检查程序的内部逻辑,绝不检查用户输入或环境。引用最后两段http://wiki.python.org/moin/UsingAssertionsEffectively ...
断言应该不用于测试可能的失败案例 由于用户输入或操作系统/环境不良而发生 失败,例如找不到文件。相反,你应该提出一个 异常,或打印错误消息,或任何适当的。一 断言只应用于自我测试的重要原因 程序是可以在编译时禁用断言。
如果使用-O选项启动Python,则断言将是 剥离,没有评估。因此,如果代码严重使用断言, 但是性能至关重要,那么就有一个转动系统 在发布版本中关闭。 (但除非确实如此,否则不要这样做 必要。科学证明,只有一些漏洞出现了 当客户使用机器并且我们希望断言帮助那里时 太。 )
考虑到这一点,实际上从来没有理由在用户代码中捕获断言,因为断言的整个失败点是尽快通知程序员程序中存在逻辑错误
答案 1 :(得分:3)
我更喜欢不在函数中捕获断言,而是确保调用者处理任何错误。这也允许调用者检查任何未处理的错误并检查回溯以确切地看出出了什么问题。
您还可以向断言语句添加错误消息。
assert x > 0, "x must be greater than 0"
答案 2 :(得分:2)
如果调用函数在成功时期望输入0而在失败时期望输入-1,我会写:
def prepare_for_connection(*args, **kwargs):
if (self.handle is not None):
return -1
if not (isinstance(port_number, int) or isinstance(port_number, float)):
return -1
if port_number < 0:
return -1
# function body
return 0
为非异常行为调用抛出和捕获断言错误的机制是过多的开销。对于语句应始终为真的情况,断言更好,但如果不是由于某些错误,则会在该位置大声生成错误,或者最好在该位置处理它(使用默认值)。如果您愿意,可以将multiple-if条件组合成一个巨大的条件语句;我个人认为这更具可读性。此外,python样式将使用None
和is
而不是is not
和==
与!=
进行比较。
一旦程序离开调试阶段,Python应该能够优化掉断言。见http://wiki.python.org/moin/UsingAssertionsEffectively
当然,这种从函数返回错误号(-1 / 0)的C风格约定并不特别pythonic。我会将-1
替换为False
,将0
替换为True
,并将其命名为具有语义意义的名称;例如,将其称为connection_prepared = prepare_for_connection(*args,**kwargs)
,因此connection_prepared
将是True
或False
,代码将非常易读。
connection_prepared = prepare_for_connection(*args,**kwargs)
if connection_prepared:
do_something()
else:
do_something_else()
答案 3 :(得分:1)
return -1
Python有一种处理错误的方法与C不同。如果提供的数据存在问题,只需让AssertionError
通过,或者提出TypeError
或ValueError
自定义错误消息。带有assert语句的自定义错误消息是最简单的:
assert port_number > 0, "Invalid port number"
可以在编译时禁用断言语句这一事实可能是重新考虑是否要在您的情况下使用断言语句的原因。通常的做法是不使用assert语句来验证函数用户的输入,而只是用于内部健全性检查。另一方面,健全性检查和验证之间的界限没有明确定义。没有断言语句的代码部分示例:
if port_number <= 0:
raise ValueError('Invalid port number')
if not isinstance(port_number, (int, float)):
raise TypeError('Port number must be some kind of number')
我个人使用assert语句来验证数据,如果无效的话,迟早会导致崩溃(参见“duck-typing”)。我还在开发期间大量使用断言语句,以便对我的数据进行完整性检查,就像它使用静态类型语言一样。如果我强烈质疑我自己的代码的稳定性和可靠性,我只会使用这些类型的断言。
下一行:
assert self.handle == None
如果我没记错的话,PEP8说你应该写assert self.handle is None
。至少它得到了比我聪明的人的支持。
assert isinstance(port_number, int) or isinstance(port_number, float)
如果你确实需要这个,可以写成isinstance(port_number, (int, float))
。但事实证明你没有。你不应该关心某人是否传递了一个数字基元类型或一些重载所有比较运算符的自制类。
也许您可以做的一件事是尝试将端口转换为整数并查看它是否可用:
try:
port_number = int(port_number)
except ValueError:
raise ValueError("Invalid port number")
同样在这种情况下你可以让ValueError
通过,但新手的消息信息量会少一些。