Python-断言与if和return


12

我正在编写一个对文本文件执行某些操作的脚本(尽管这样做与我的问题无关)。因此,在对文件执行某些操作之前,我想检查文件是否存在。我可以做到,没问题,但是问题更多是美学问题。

这是我的代码,以两种不同的方式实现同​​一件事。

def modify_file(filename):
    assert os.path.isfile(filename), 'file does NOT exist.'


Traceback (most recent call last):
  File "clean_files.py", line 15, in <module>
    print(clean_file('tes3t.txt'))
  File "clean_files.py", line 8, in clean_file
    assert os.path.isfile(filename), 'file does NOT exist.'
AssertionError: file does NOT exist.

要么:

def modify_file(filename):
    if not os.path.isfile(filename):
        return 'file does NOT exist.'


file does NOT exist.

第一种方法产生的输出大部分都是微不足道的,我唯一关心的是该文件不存在。

第二种方法返回一个字符串,很简单。

我的问题是:哪种方法最好让用户知道该文件不存在?使用该assert方法似乎更像pythonic。

Answers:


33

您可以选择第三个选项:use raise和特定的例外。这可以是内置异常之一,也可以为作业创建自定义异常。

在这种情况下,我会使用IOError,但ValueError也可能适合:

def modify_file(filename):
    if not os.path.isfile(filename):
        raise IOError('file does NOT exist.')

使用特定的异常可以使您针对不同的特殊情况引发其他异常,并允许调用方优雅地处理该异常。

当然,许多文件操作(例如open()本身OSError已经引发;明确地首先测试文件是否存在在这里可能是多余的。

不要用assert; 如果您使用-O标记运行python,则会从代码中剥离所有断言。


关于冗余的有趣观点!您是否建议避免这种情况?即“无论如何以后都会失败”
CiprianTomoiagă18年

1
@CiprianTomoiagă:为什么要加倍进行测试?如果的下一行modify_file()with open(filename) as f:,则IOError也将引发。而且,最新的Python版本在IOErrorFileNotFoundError特别是我想到的)子类中提供了更多详细信息,这可能会对使用此API的开发人员有所帮助。如果代码自己检查并引发,IOError那么有用的细节将丢失。
马丁·彼得斯

@MartijnPieters将回答“为什么要加倍进行测试?” 什么时候第一次检查比open()失败时引发的异常更快?例如,检查文件是否存在比尝试打开并最终失败的速度更快。
马塞尔·威尔逊

1
@MarcelWilson:不,因为您将针对执行I / O的方法进行微优化。在微小的Python语义上进行大量调整不会使I / O更快,只会损害可读性和可维护性。我会说,着眼于影响更大的领域。
Martijn Pieters

12

assert适用于调用函数的程序员用户相反的情况。assert在这种情况下使用,可以确保程序员在测试期间正确使用了您的函数,然后在生产中将其剥离。

由于必须确保您在代码中使用该路径,因此它的价值受到一定程度的限制,并且您通常想if在生产中使用单独的语句来另外处理该问题。 assert在以下情况下最有用:“如果用户遇到此问题,我想帮助解决此问题,但是如果开发人员遇到此问题,我希望它崩溃严重,以便他修复错误地调用此函数的代码。”

在您的特定情况下,丢失文件几乎肯定是用户错误,应该通过引发异常来处理。


5

有效地使用断言

检查isinstance()不应过度使用:如果它像鸭子一样发出嘎嘎叫声,则可能无需深入询问是否确实如此。有时,传递原始程序员未预期的值会很有用。

考虑放置断言的地方:

checking parameter types, classes, or values
checking data structure invariants
checking "can't happen" situations (duplicates in a list, contradictory state variables.)
after calling a function, to make sure that its return is reasonable 

总的来说,如果出了问题,我们希望尽快使它变得完全显而易见。

在输入错误数据时捕获错误数据要比在以后引起问题时确定错误数据的到达位置容易。

断言不能代替单元测试或系统测试,而是一种补充。因为断言是检查对象或函数内部状态的一种干净方法,所以断言“免费”为检查外部行为的黑盒测试提供了明确的帮助。

断言应用于测试由于用户输入错误或操作系统/环境故障(例如找不到文件)而导致的故障情况。相反,您应该引发异常,或显示错误消息,或其他适当的方法。断言只能用于程序自检的重要原因之一是断言可以在编译时禁用。

如果Python使用-O选项启动,则断言将被剥离并且不进行评估。因此,如果代码大量使用断言,但对性能至关重要,则可以使用一个系统在发行版本中将其关闭。(但是除非确实必要,否则不要这样做。科学证明,只有当客户使用机器时,才会出现一些错误,我们也需要断言来帮助您。:-))

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.