资讯专栏INFORMATION COLUMN

Python中的上下文管理器和else块

Michael_Lin / 2717人阅读

摘要:上下文管理器协议包含和两个方法。因此必要时在上下文管理器函数中使用语句防范错误。构建临时忽略指定异常的上下文管理器。这是个基类,用于定义基于类的上下文管理器。块结束时,按照后进先出的顺序调用栈中各个上下文管理器的方法。

导语:本文章记录了本人在学习Python基础之控制流程篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。

本文重点:

1、掌握if语句之外的else的用法;
2、掌握上下文管理器的定义、协议、使用和with块;
3、掌握有用的@contextmanger装饰器。
一、if语句之外的else块 1、else块介绍

if/else中if和else是同级对立的语句,对立是指流程经过一层if/else语句只能对应一种处理语句。而else在for/else,while/else,try/else语句中的功能则截然不同。后者中的else功能如下:

for/else:for循环没有被break语句中止才运行else块。

while/else:while循环没有被break语句中止才运行else块。

try/else:try块中,没有异常抛出时才运行else块。

下面以for/else为例进行代码实现:

for i in "apple":
    if i.isupper():
        break
else:
    raise ValueError("No upper string was found")
2、try/else块背后的编程风格

try/except不仅用于处理错误,还用于处理错误,这属于EAFP编程风格。

EAFP:easier to ask for forgiveness than permission
取得原谅比获得许可容易。即先假定存在有效的键或属性,如果假定不成立,那么捕获异常。

LBYL:look before you leap
三思而后行。即在调用函数或查找属性或键之前显式测试前提条件。

二、上下文管理器和with块 1、上下文管理器介绍

上下文管理器(context manger):在操作文件和建立数据库连接的时候,我们最终需要关闭资源,这就是上下文管理器存在的意义。
上下文管理器协议:包含__enter__和__exit__两个方法。
语法:try/finally模式和with语句
实例:try/finally模式

try:
    f = open("test.txt", "a+")
    f.write("Foo
")
finally:
    f.close()

接下来我们用with语句进行替换:
实例:with语句

with open("test.txt", "a+") as f:
    f.write("Foo
")

分析:open 的返回值赋值给变量 f,当离开 with 代码块的时候,系统会自动调用 f.close() 方法。
总结:with块的功能在于简化try/finally模式。with语句在开始运行时会在上下文管理器对象上调用__enter__,而with语句结束时会调用__exit__方法。
Tips:with语句中的as语句是可选的,as语句将__enter__返回的值绑定到as语句后的变量。值得注意的是,对于open函数必须加上as字句来获取文件的引用。

2、自定义上下文管理器

在掌握基本上下文管理器和with语句后,我们通过自定义上下文管理器来深刻认识with语句和__enter__以及__exit__的联系。
实例:自定义满足上下文管理器协议的类

class OpenFileDemo(object):
    def __init__(self, filename):
        self.filename = filename
 
        self.f = open(self.filename, "a+")
        return self.f
 
    def __exit__(self, exc_type, exc_value, traceback):
        self.f.close()
        if exc_type != SyntaxError:
            return True
       return False

with OpenFileDemo("test.txt") as f:
    f.write("Foo
")
3、异常处理

当上下文管理器遇到异常时由__exit__方法处理。传给__exit__方法的三个参数如下:
exc_type:异常类(例如SyntaxError)。
exc_value:异常实例。有时会有参数传给异常构造方法,例如错误信息,可以使用exc_value.args获取这些参数。
traceback:traceback对象。

三、@contextmanger装饰器

@contextmanger装饰器是contextlib模块中的工具,它可以将包含yield的语句变成上下文管理器。
其中,yield之前的语句在__enter__方法中执行yield之后的语句在__exit__方法执行,yield后面的值是函数的返回值,绑定到实际调用的with中的as子句的目标变量上
如此可以避免编写一个类来实现上下文管理器协议。

实例:@contextmanger装饰器应用之计时器

import contextlib
import time

@contextlib.contextmanager
def timer():
    start=time.time()
    yield
    end=time.time()
    usedtime=end-start
    print("Running time was %r seconds"%usedtime)

with timer() as usedtime:
    time.sleep(1)

注意:一旦with块在调用timer出现异常时,抛出的异常会在timer函数中的yield表达式中再次抛出。如果timer函数没有处理异常的代码就会导致函数运行中止,系统处于无效状态。因此必要时在上下文管理器函数中使用try/finally语句防范错误。

@contextmanger集合了三个不同的Python特性:函数装饰器、生成器和with语句,非常实用!

四、contextlib模块中的实用工具

最后说明contextlib模块中包含的实用工具:

closing: 如果对象提供了 close() 方法,但没有实现 _enter__/__exit_ 协议,那么可以使用这个函数构建上下文管理器。

suppress: 构建临时忽略指定异常的上下文管理器。

@contextmanager: 这个装饰器把简单的生成器函数变成上下文管理器,这样就不用创建类去实现管理器协议了。

ContextDecorator: 这是个基类,用于定义基于类的上下文管理器。这种上下文管理器也能用于装饰函数,在受管理的上下文中运行整个函数。

ExitStack: 这个上下文管理器能进入多个上下文管理器。with 块结束时,ExitStack 按照后进先出的顺序调用栈中各个上下文管理器的_exit_ 方法。如果事先不知道 with 块要进入多少个上下文管理器,可以使用这个类。例如,同时打开任意一个文件列表中的所有文件。

显然,在这些实用工具中,使用最广泛的是 @contextmanager 装饰器,因此要格外留心。这个装饰器也有迷惑人的一面,因为它与迭代无关,却要使用 yield 语句。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/44555.html

相关文章

  • 下文管理器和 else

    摘要:上下文管理器和块上下文管理器协议包含和两个方法。语句运行结束后,会在上下文管理器对象上调用方法,以此扮演子句的角色。 上下文管理器 最终,上下文管理器可能几乎与子程序(subroutine)本身一样重要。 在各种语言中 with 语句的作用不同,而且做的都是简单的事,虽然可以避免不断使用点号查找属性,但是不会做事前准备和事后清理。 if语句之外的else块 else太个性了, 其他语言...

    bbbbbb 评论0 收藏0
  • Python入门学习笔记汇总

    摘要:导语本文章汇总了本人在学习基础之绪论篇数据结构篇函数篇面向对象篇控制流程篇和元编程篇学习笔记的链接,打算入门的朋友们可以按需查看并交流。 导语:本文章汇总了本人在学习Python基础之绪论篇、数据结构篇、函数篇、面向对象篇、控制流程篇和元编程篇学习笔记的链接,打算入门Python的朋友们可以按需查看并交流。 第一部分:绪论篇 1、Python数据模型 第二部分:数据结构篇 2、序列构成...

    U2FsdGVkX1x 评论0 收藏0
  • 生成器进化到协程 Part 2

    摘要:一个典型的上下文管理器类如下处理异常正如方法名明确告诉我们的,方法负责进入上下的准备工作,如果有需要可以返回一个值,这个值将会被赋值给中的。总结都是关于上下文管理器的内容,与协程关系不大。 Part 1 传送门 David Beazley 的博客 PPT 下载地址 在 Part 1 我们已经介绍了生成器的定义和生成器的操作,现在让我们开始使用生成器。Part 2 主要描述了如...

    fuyi501 评论0 收藏0
  • 异步等待的 Python 协程

    摘要:辅之以事件循环,协程可用于异步处理,尤其是在中。当前支持的协程基于增强型生成器,于版本开始采用。新的特性中,异步还有两种新用途异步内容管理器和迭代器。 现在 Python 已经支持用协程进行异步处理。但最近有建议称添加协程以全面完善 Python 的语言结构,而不是像现在这样把他们作为生成器的一个类型。此外,两个新的关键字———异步(async)和等待(await),都该添加到 Pyt...

    NicolasHe 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<