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

par*_*rks 73 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
Run Code Online (Sandbox Code Playgroud)

另一个选择是保留异常并在调用者代码中处理它,但我认为处理a FileNotFoundError比处理它更清楚IndexError.或者用不同的名称重新引发异常是不好的形式?

Eev*_*vee 82

这真的是一个语义问题.什么foo = latestpdf(d) 意思

没有最新文件是完全合理的吗?那么肯定,只返回None.

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

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

  • 需要考虑的另一点:如果引发异常,则可以附加一条消息,但是当返回`None'时我们不能这样做。 (3认同)

rh0*_*ium 7

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

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

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

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

for folder in folders:
   try:
       latest = getLatestPdfFromFolder(folder)
       results = somefuc(latest)
   except IOError: pass
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!

  • 或者`get_latest_pdf_from_folder`。事实上,Pep8:“函数名称应该小写,单词之间用下划线分隔,以提高可读性。” (2认同)

Asa*_*saf 6

使用 python 3.5 的输入

返回 None 时的示例函数将是:

def latestpdf(folder: str) -> Union[str, None]
Run Code Online (Sandbox Code Playgroud)

引发异常时将是:

def latestpdf(folder: str) -> str 
Run Code Online (Sandbox Code Playgroud)

选项 2 看起来更具可读性和Python风格

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

  • `Union[str, None]` 应该是 `Optional[str]` (8认同)
  • 速记,但你是对的,它更具可读性。不编辑,所以两个选项都在这里。 (2认同)
  • 2 可能更具可读性,但(不幸的是?)类型提示并不表明可能引发异常。我最近发现 1 将有助于捕获更多错误,因为您被迫处理 None 返回。 (2认同)

Dav*_*ger 5

我通常更喜欢在内部处理异常(即在被调用函数内部进行try / except,可能返回None),因为python是动态类型的。总的来说,我认为这是一种判断调用方式,但是在动态类型的语言中,有一些小因素会提示扩展规模,以免将异常传递给调用者:

  1. 不会向任何调用您函数的人通知可能引发的异常。知道您正在寻找什么样的异常(以及应该避免的一般性例外),成为一种艺术形式。
  2. if val is None比容易一点except ComplicatedCustomExceptionThatHadToBeImportedFromSomeNameSpace。严重的是,我讨厌不得不记住from django.core.exceptions import ObjectDoesNotExist在所有django文件的顶部键入内容,只是为了处理一个非常常见的用例。在静态类型的世界中,让编辑器为您完成。

不过,老实说,它始终是一个判断调用,而您所描述的情况(被调用函数收到它无法帮助的错误)是重新引发有意义的异常的极好理由。您有完全正确的想法,但除非有例外,否则您将在堆栈跟踪中提供比

AttributeError: 'NoneType' object has no attribute 'foo'
Run Code Online (Sandbox Code Playgroud)

如果您返回未处理的None(无),则打扰者将看到呼叫的结果,十分之九。

(所有这些使我希望python异常在cause默认情况下具有属性,就像在Java中一样,它使您可以将异常传递到新的异常中,以便您可以抛弃所有想要的东西,而不会丢失问题的原始来源。)