在Python中用户定义的函数中有什么更好的做法:raise
例外或return None
?例如,我有一个函数可以找到文件夹中的最新文件。
def latestpdf(folder):
# list the files and sort them
try:
latest = files[-1]
except IndexError:
# Folder is empty.
return None # One possibility
raise FileNotFoundError() # Alternative
else:
return somefunc(latest) # In my case, somefunc parses the filename
另一种选择是保留异常并在调用者代码中处理它,但我认为处理FileNotFoundError
而不是IndexError
更为明确。或者用不同的名称重新引发异常是不好的形式?
答案 0 :(得分:78)
这真的是语义问题。 foo = latestpdf(d)
意味着什么?
没有最新文件是否完全合理?那么肯定,只返回无。
您是否希望始终找到最新的文件?提出例外。是的,重新提出一个更合适的例外是可以的。
如果这只是一个应该应用于任何目录的通用函数,我会做前者并返回None。如果目录是例如包含应用程序已知文件集的特定数据目录,我会引发异常。
答案 1 :(得分:7)
在回答你的问题之前我会提出一些建议,因为它可能会为你回答这个问题。
latestpdf
对任何人都意味着很少,但查看您的函数latestpdf()
会获得最新的pdf。我建议您将其命名为getLatestPdfFromFolder(folder)
。我一做到这一点就很清楚它应该返回什么..如果没有pdf引发异常。但是等一下......
for folder in folders:
try:
latest = getLatestPdfFromFolder(folder)
results = somefuc(latest)
except IOError: pass
希望这有帮助!
答案 2 :(得分:5)
我通常更喜欢在内部处理异常(即在被调用函数内部尝试/除外,可能返回None)因为python是动态类型的。一般来说,我认为它是一种判断调用方式,但是在动态类型语言中,有一些小因素会使得这些因素不会将异常传递给调用者:
if val is None
比except ComplicatedCustomExceptionThatHadToBeImportedFromSomeNameSpace
容易一些。说真的,我讨厌必须记住在我所有的django文件的顶部键入from django.core.exceptions import ObjectDoesNotExist
只是为了处理一个非常常见的用例。在一个静态类型的世界中,让编辑为你做。老实说,它总是一个判断调用,而你所描述的情况,被调用的函数收到一个它无法帮助的错误,是重新提出有意义的异常的一个很好的理由。你有完全正确的想法,但除非你是例外,否则将在堆栈跟踪中提供比
更有意义的信息AttributeError: 'NoneType' object has no attribute 'foo'
,如果你返回一个未处理的无,调用者将会看到的是九次中的九次,不要打扰。
(所有这些让我希望python异常默认具有cause
属性,就像在java中一样,它允许你将异常传递给新的异常,这样你就可以重新抛出你想要的所有东西,永远不会失去原来的问题的根源。)
答案 3 :(得分:2)
一般情况下,我会说如果发生无法恢复的灾难性事件(即你的函数处理一些无法连接的互联网资源),应该抛出异常,如果你的函数应该返回,你应该返回None真的返回一些东西,但没有什么是适合返回的(例如,如果你的函数试图匹配字符串中的子字符串,则为“无”)。
答案 4 :(得分:0)
使用python 3.5的typing:
返回无时的示例函数为:
date units snowfall preciptotal event
store_nbr item_nbr
1 1 2012-01-01 0 0.0 0.0 0.0
2 2012-01-01 0 0.0 0.0 0.0
3 2012-01-01 0 0.0 0.0 0.0
4 2012-01-01 0 0.0 0.0 0.0
5 2012-01-01 0 0.0 0.0 0.0
,并且在引发异常时将是:
def latestpdf(folder: str) -> Union[str, None]
选项2似乎更具可读性和pythonic
(+选项,如前所述,为异常添加注释。)