python怎么将if和try一起用_Python使用try/catch还if效率更高一些?

“请求原谅”和“三思而后行”(有时也称为“请求许可”)是编写代码的两种相反的方法。如果你“三思而后行”,你首先要检查一切是否设置正确,然后再执行一个操作。例如,您要从文件中读取文本。那会出什么问题呢?好吧,文件可能不在您期望的位置。因此,首先检查文件是否存在:

import os

if os.path.exists("path/to/file.txt"):

...

# Or from Python 3.4

from pathlib import Path

if Path("/path/to/file").exists():

...

即使文件存在,也许你没有打开它的权限?所以让我们看看你是否能读到:

import os

if os.access("path/to/file.txt", os.R_OK):

...

但是如果文件损坏了怎么办?或者你没有足够的内存去读它?这个名单可以继续下去。最后,当你认为你检查了每一个可能的问题,你可以打开并阅读它:

with open("path/to/file.txt") as input_file:

return input_file.read()

根据您要执行的操作,可能需要执行很多检查。即使你认为你已经涵盖了所有内容,也不能保证某些意外的问题不会阻止你阅读此文件。所以,你可以“请求原谅”,而不是做所有的检查

有了“请求原谅”,你什么都不检查。您可以执行您想要的任何操作,但将其包装在try/catch块中。如果发生异常,则处理它。您不必考虑所有可能出错的地方,您的代码要简单得多(没有更多嵌套的ifs),而且这样通常会捕获更多的错误。这就是为什么Python社区通常更喜欢这种方法,通常称为“EAFP”——“请求原谅比请求许可更容易。”

下面是一个使用“请求原谅”方法读取文件的简单示例:

try:

with open("path/to/file.txt", "r") as input_file:

return input_file.read()

except IOError:

# Handle the error or just ignore it

这里我们正在捕捉IOError。如果您不确定可以引发哪种类型的异常,可以使用BaseException类捕捉所有异常,但一般来说,这是一种不好的做法。它将捕捉所有可能的异常(例如,当你想停止进程时,包括KeyboardInterrupt),所以尽量更具体一些。

“请求原谅”更干净。但是哪一个更快?

“请求原谅”与“三思而后行”-速度

是时候做个简单的测试了。假设我有一个类,我想从这个类中读取一个属性。但是我使用的是继承,所以我不确定是否定义了属性。我需要保护自己,要么检查它是否存在(“三思而后行”),要么抓住AttributeError(“请求原谅”):

# permission_vs_forgiveness.py

class BaseClass:

hello = "world"

class Foo(BaseClass):

pass

FOO = Foo()

# Look before you leap

def test_lbyl():

if hasattr(FOO, "hello"):

FOO.hello

# Ask for forgiveness

def test_aff():

try:

FOO.hello

except AttributeError:

pass

我们来测量这两个函数的速度。

$ python -m timeit -s "from permission_vs_forgiveness import test_lbyl" "test_lbyl()"

2000000 loops, best of 5: 155 nsec per loop

$ python -m timeit -s "from permission_vs_forgiveness import test_aff" "test_aff()"

2000000 loops, best of 5: 118 nsec per loop

你先看一下,再慢一点。

如果我们增加检查数量会怎么样?假设这次我们要检查三个属性,而不仅仅是一个:

# permission_vs_forgiveness.py

class BaseClass:

hello = "world"

bar = "world"

baz = "world"

class Foo(BaseClass):

pass

FOO = Foo()

# Look before you leap

def test_lbyl2():

if hasattr(FOO, "hello") and hasattr(FOO, "bar") and hasattr(FOO, "baz"):

FOO.hello

FOO.bar

FOO.baz

# Ask for forgiveness

def test_aff2():

try:

FOO.hello

FOO.bar

FOO.baz

except AttributeError:

pass

$ python -m timeit -s "from permission_vs_forgiveness import test_lbyl2" "test_lbyl2()"

500000 loops, best of 5: 326 nsec per loop

$ python -m timeit -s "from permission_vs_forgiveness import test_aff2" "test_aff2()"

2000000 loops, best of 5: 176 nsec per loop

“三思而后行”现在大约慢了85%(326/176≈1.852)。所以“请求原谅”不仅更容易阅读,而且在很多情况下,速度也更快。是的,你读得对,“在很多情况下,”不是“在所有情况下”!”

“EAFP”和“LBYL”的主要区别

如果属性实际上没有定义,会发生什么?看看这个例子:

# permission_vs_forgiveness.py

class BaseClass:

pass # "hello" attribute is now removed

class Foo(BaseClass):

pass

FOO = Foo()

# Look before you leap

def test_lbyl3():

if hasattr(FOO, "hello"):

FOO.hello

# Ask for forgiveness

def test_aff3():

try:

FOO.hello

except AttributeError:

pass

$ python -m timeit -s "from permission_vs_forgiveness import test_lbyl3" "test_lbyl3()"

2000000 loops, best of 5: 135 nsec per loop

$ python -m timeit -s "from permission_vs_forgiveness import test_aff3" "test_aff3()"

500000 loops, best of 5: 562 nsec per loop

形势已经好转。“请求原谅”现在是“三思而后行”的四倍多(562/135≈4.163)。这是因为这一次,我们的代码抛出了一个异常。而且处理异常的成本很高。

如果您希望您的代码经常失败,那么“三思而后行”可能会快得多。

决断

“请求原谅”的结果是代码更简洁,更容易发现错误,而且在大多数情况下,速度更快。难怪EAFP(“请求原谅比请求许可更容易”)在Python中是如此普遍的模式。即使在本文开头的示例中(检查文件是否存在os.path.exists)-如果您查看exists方法的源代码,就会发现它只是使用try/except。“三思而后行”通常会导致代码较长,可读性较差(使用嵌套的if语句)且速度较慢。按照这种模式,你有时可能会漏掉一两个判断。

请记住,处理异常是缓慢的。扪心自问:“这段代码是否会抛出异常更常见?如果答案是“是”,你可以用一个好的“IF”来解决这些问题,太好了!但在很多情况下,你无法预测你会遇到什么问题。使用“请求原谅”是非常好的-在你开始加速之前,你的代码应该是“正确的”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值