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

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”来解决这些问题,太好了!但在很多情况下,你无法预测你会遇到什么问题。使用“请求原谅”是非常好的-在你开始加速之前,你的代码应该是“正确的”。

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

  1. python3 循环写入一对多键值对_为什么Python 3.6以后字典有序并且效率更高?

    在Python 3.5(含)以前,字典是不能保证顺序的,键值对A先插入字典,键值对B后插入字典,但是当你打印字典的Keys列表时,你会发现B可能在A的前面. 但是从Python 3.6开始,字典是变成 ...

  2. python3.6字典有序_为什么从Python 3.6开始字典有序并效率更高

    在Python 3.5(含)以前,字典是不能保证顺序的,键值对A先插入字典,键值对B后插入字典,但是当你打印字典的Keys列表时,你会发现B可能在A的前面. 但是从Python 3.6开始,字典是变成 ...

  3. python3.6字典有序_为什么Python 3.6以后字典有序并且效率更高?

    在Python 3.5(含)以前,字典是不能保证顺序的,键值对A先插入字典,键值对B后插入字典,但是当你打印字典的Keys列表时,你会发现B可能在A的前面. 但是从Python 3.6开始,字典是变成 ...

  4. python排版word文档 效率_「word技巧」懂得这几个word排版小技巧,还怕效率不高?...

    熟能生巧.作为一名职场人,使用word是不可避免的.Word玩得遛,工作效率就提高了.不过想要把word玩得遛,掌握一些技巧必不可少. 今天就来看看word排版上经常要用到的几个小技巧. 一.好用的F ...

  5. python安装matplotlib需要c编译_在Python 3.9上安装matplotlib提示需要FreeType更高版本的解决...

    在Python 3.9(在Deepin系统中采用源码安装Python 3.9版本的方法)上安装matplotlib提示需要FreeType 2.3或更高版本,可以将MPLLOCALFREETYPE环境 ...

  6. python中123+5.0的执行结果_python实战笔记(一)

    [Python注释] [Python变量] [Python运算符] [Python输入输出] *   [输入函数] *   [输出函数(3.x)] *   [格式化输出] [分支] [循环] ### ...

  7. python的特性注定了代码无法保密_python 基础

    谈谈你对python和其他语言的区别 python 中,变量是以内容为基准而不是像 c 中以变量名为基准: python 中,一个变量可以以多个名称访问: python 中,数字类型的值是不可变的: ...

  8. python 协程可以嵌套协程吗_Python实战异步爬虫(协程)+分布式爬虫(多进程)

    引言:我们在写爬虫时常会遇到这样的问题,当需要爬取多个URL时,写一个普通的基于requests库的爬虫程序爬取时间会很长.因为是顺序请求网页的,而网页请求和获得响应过程比较耗费时间,程序不得不等待获 ...

  9. python矩阵拼接_numpy数组拼接简单示例_python

    这篇文章主要介绍了numpy数组拼接简单示例,涉及对numpy数组的介绍,numpy数组的属性等内容,具有一定借鉴价值,需要的朋友可以参考下. NumPy数组是一个多维数组对象,称为ndarray.其 ...

最新文章

  1. dedecms织梦专题节点列表内容怎么实现分页
  2. list index out of range怎么解决_“卿卿我我”和“如胶似漆”英语怎么说?
  3. hdu 5072 Coprime
  4. 与年轻人的“要疯”五年,安踏如何保持新鲜感与吸引力?
  5. java的继承_java中的继承(一)
  6. 如果测试你的MongoDB应用升级?
  7. python3.8学习_python3.8.1 入门基础学习 之 【字典】 学习
  8. 到无限(溪流)和超越!
  9. QML笔记-整合C++及单例模式管理QML中控件
  10. I2C 协议分析和学习
  11. 4KB/2MB PAE分页模式下的线性地址翻译以及CR3
  12. 看电影的计算机配置,专门看电影的电脑主机需要什么配置?
  13. 轻量容器和注射依赖 的自实现
  14. JQuery each详细用法
  15. MIPI D-PHY IP 使用说明(二)
  16. c++避坑指南-除数为0
  17. linux蓝牙打印机驱动安装失败怎么办,打印机驱动安装失败怎么办?
  18. mysql数据库的主从同步(主服务器存在内网IP)
  19. Pycharm使用远程服务器解释器
  20. Flowable Exclusive gateway has no outgoing sequence flow

热门文章

  1. Hadoop之Yarn工作机制详解
  2. 大剑无锋之Redis面试题【推荐】
  3. Error: Could not open client transport with JDBC Uri: jdbc:hive2://henu2:10000: java.n et.ConnectExc
  4. 爬虫 spider05——使用httpclient发送get请求、post请求
  5. map反转key value
  6. 数据分析-pands分析美国选民对总统的喜好(python实现)
  7. gradle的多项目构建(九)
  8. 蓝桥杯 ADV-202 算法提高 最长公共子序列
  9. 大话主题敏感PageRank
  10. jQuery事件3——trigger触发事件