提升异常与返回函数中没有?

时间:2009-08-21 19:28:20

标签: python exception-handling

在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更为明确。或者用不同的名称重新引发异常是不好的形式?

5 个答案:

答案 0 :(得分:78)

这真的是语义问题。 foo = latestpdf(d) 意味着什么

没有最新文件是否完全合理?那么肯定,只返回无。

您是否希望始终找到最新的文件?提出例外。是的,重新提出一个更合适的例外是可以的。

如果这只是一个应该应用于任何目录的通用函数,我会做前者并返回None。如果目录是例如包含应用程序已知文件集的特定数据目录,我会引发异常。

答案 1 :(得分:7)

在回答你的问题之前我会提出一些建议,因为它可能会为你回答这个问题。

  • 始终将您的功能命名为描述性的。 latestpdf对任何人都意味着很少,但查看您的函数latestpdf()会获得最新的pdf。我建议您将其命名为getLatestPdfFromFolder(folder)

我一做到这一点就很清楚它应该返回什么..如果没有pdf引发异常。但是等一下......

  • 保持功能明确。因为不明显是某些人应该做什么,并且(显然)显然它与获取最新的pdf有什么关系我建议你把它移出去。这使代码更具可读性。

for folder in folders:
   try:
       latest = getLatestPdfFromFolder(folder)
       results = somefuc(latest)
   except IOError: pass

希望这有帮助!

答案 2 :(得分:5)

我通常更喜欢在内部处理异常(即在被调用函数内部尝试/除外,可能返回None)因为python是动态类型的。一般来说,我认为它是一种判断调用方式,但是在动态类型语言中,有一些小因素会使得这些因素不会将异常传递给调用者:

  1. 任何调用您函数的人都不会收到可抛出异常的通知。知道你正在寻找什么样的例外情况变成了一种艺术形式(除了应该避免使用块之外的通用)。
  2. if val is Noneexcept ComplicatedCustomExceptionThatHadToBeImportedFromSomeNameSpace容易一些。说真的,我讨厌必须记住在我所有的django文件的顶部键入from django.core.exceptions import ObjectDoesNotExist只是为了处理一个非常常见的用例。在一个静态类型的世界中,让编辑为你做。
  3. 老实说,它总是一个判断调用,而你所描述的情况,被调用的函数收到一个它无法帮助的错误,是重新提出有意义的异常的一个很好的理由。你有完全正确的想法,但除非你是例外,否则将在堆栈跟踪中提供比

    更有意义的信息
    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

(+选项,如前所述,为异常添加注释。)