为什么在Python中“更容易请求宽恕而不是获得权限”?

问题描述 投票:4回答:3

为什么“更容易请求宽恕而不是获得权限”(EAFP)被认为是Python中的好习惯?作为编程新手,我的印象是,与使用其他检查相比,使用许多try...except例程将导致臃肿且可读性较低的代码。

EAFP方法的优势是什么?

注意:我知道这里有类似的问题,但它们主要是指一些具体的例子,而我对这个原则背后的哲学更感兴趣。

python coding-style
3个回答
4
投票

LBYLEAFP的反制方法与断言没有任何关系,它只是意味着你在尝试访问可能不存在的东西之前添加一个检查。

Python是EAFP的原因与其他语言(例如Java)不同 - 在Python中捕获异常是相对便宜的操作,这就是为什么鼓励你使用它。

EAFP示例:

try:
    snake = zoo['snake']
except KeyError as e:
    print "There's no snake in the zoo"
    snake = None

LBYL的示例:

if 'snake' in zoo:
    snake = zoo['snake']
else:
    snake = None

3
投票

你在这里混合两件事:断言和基于EAFP的逻辑。

断言用于验证函数的约定,即它的前后条件,有时还有它的不变量。它们确保以应该使用的方式使用函数。它们不适用于代码流,因为它们完全中断了错误执行。一个常见的例子是检查函数调用中的None参数。

在Python中,通常避免使用过多的断言。通常,您应该希望代码的用户正确使用它。例如,如果您记录一个函数来获取不是None的参数,那么就没有必要使用一个验证该参数的断言。相反,只是期望有一个价值。如果由于None值而出现错误,那么无论如何它都会冒泡,因此用户知道他们做错了什么。但你不应该一直检查所有内容。

现在,EAFP是不同的东西。它用于控制流程,或者更确切地说,它避免了额外的控制流程,有利于期望事情正确并且如果不是则捕获异常。显示差异的常见示例是字典中的密钥访问:

# LBYL
if key in dic:
    print(dic[key])
else:
    handleError()

# EAFP
try:
    print(dic[key])
except KeyError:
    handleError()

现在看起来非常相似,但你应该记住LBYL解决方案检查字典两次。与捕获异常的所有代码一样,只有在不存在密钥的情况下才应该这样做。因此,如果通常情况下,提供的密钥不在字典中,那么它是EAFP,您应该直接访问它。如果你不希望密钥存在于字典中,那么你应该首先检查它的存在(虽然异常在Python中更便宜,但它们仍然不是免费的,所以请保留它们以用于特殊情况)。

EAFP的好处还在于你的库或应用程序的逻辑更深层次,key来自上面,你可以假设这里传递了一个有效的密钥。所以你不需要在这里捕获异常,只是让它们冒泡到代码中的更高点,然后你可以处理错误。这使您可以完全免除这些检查的低级功能。


1
投票

好问题! StackOverflow中很少有人质疑“原则背后的哲学”。

关于EAFP definition in Python glossary,我甚至会更进一步说它提到“如果假设证明是错误的,则缓存异常”在这种情况下有些误导。因为,让我们面对它,下面的第二个代码片段看起来不那么“干净和快速”(在上述定义中使用的术语)。难怪OP问这个问题。

# LBYL
if key in dic:
    print(dic[key])
else:
    handleError()

# EAFP
try:
    print(dic[key])
except KeyError:
    handleError()

我想说,EAFP闪耀的真正时刻是,你根本不写try ... except ...,至少在你的大多数底层代码库中都没有。因为,the first rule of exception handling: do not do exception handling。考虑到这一点,现在,让我们将第二个片段重写为:

# Real EAFP
print(dic[key])

现在,这不是真正的EAFP方法干净而快速吗?

© www.soinside.com 2019 - 2024. All rights reserved.