文档章节

with 的高级用法

 阿豪boy
发布于 06/24 22:48
字数 1204
阅读 6
收藏 0
点赞 0
评论 0

那么 上下文管理器 又是什么呢?

上下文管理器协议包含 __enter__ 和 __exit__ 两个方法。with 语句开始运行时,会在上下文管理器对象上调用 __enter__ 方法。with 语句运行结束后,会在上下文管理器对象上调用 __exit__ 方法,以此扮演 finally 子句的角色。最常见的例子是确保关闭文件对象(示例1)。

下面我们实现一个简单的例子来直观的感受一下:

class T:
    def __enter__(self):
        print('T.__enter__')
        return '我是__enter__的返回值'
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('T.__exit__')

with T() as t:
    print(t)

输出:

T.__enter__
我是__enter__的返回值
T.__exit__

示例3中实现了一个类T,它的对象包含了__enter__和__exit__方法,有了这两个方法就可以使用 with 处理该对象。执行 with 后面的表达式T()得到的是上下文管理器对象,通过as字句把对象绑定到了变量t上。

观察输出结果,可以看到with块先调用了__enter__方法,在处理完内部逻辑(print(t))之后调用了exit方法,而t其实就是__enter__方法的返回值。

当然,这个例子只是为了方便我们理解上下文管理器,下面我们看一个更有意思的例子:

示例4

obj1 = HaHa('你手机拿反了')
with obj1 as content:
    print('哈哈镜花缘')
    print(content)
print('#### with 执行完毕后,再输出content: ####')
print(content)

输出:

缘花镜哈哈
了反拿机手你
#### with 执行完毕后,在输出content: ####
你手机拿反了

示例4中,上下文管理器是 HaHa 类的实例,Python 调用此实例的 __enter__ 方法,把返回结果绑定到 变量content 上。

打印一个字符串,然后打印 content 变量的值。可以看到打印出的内容都是是反向的。

最后,当 with 块已经执行完毕。可以看出,__enter__ 方法返回的值——即存储在 content 变量中的值——是字符串 ‘你手机拿反了’。
输出不再是反向的了。

HaHa类的实现:

import sys

class HaHa:

    def __init__(self, word):
        self.word = word

    def reverse_write(self, text):
        self.original_write(text[::-1])

    def __enter__(self):
        self.original_write = sys.stdout.write
        sys.stdout.write = self.reverse_write
        return self.word

    def __exit__(self, exc_type, exc_value, traceback):
        sys.stdout.write = self.original_write
        return True

在__enter__方法中,我们接管了标准输出,将其替换成我们自己编写的方法reverse_write,reverse_write方法将参数内容反转。而在__exit__方法中,我们将标准输出还原。__exit__方法需要返回True。

总之,with之于上下文管理器,就像for之于迭代器一样。with就是为了方便上下文管理器的使用。

上下文管理器特性在标准库中有一些应用:

  • 在 sqlite3 模块中用于管理事务;

  • 在 threading 模块中用于维护锁、条件和信号;


另外,说到上下文管理器就不得不提一下@contextmanager 装饰器,它能减少创建上下文管理器的样板代码量,因为不用编写一个完整的类,定义 __enter__和 __exit__ 方法,而只需实现有一个 yield 语句的生成器,生成想让 __enter__ 方法返回的值。

在使用 @contextmanager 装饰的生成器中,yield 语句的作用是把函数的定义体分成两部分:

  1. yield 语句前面的所有代码在 with 块开始时(即解释器调用 __enter__ 方法时)执行

  2.  yield 语句后面的代码在with 块结束时(即调用 __exit__ 方法时)执行。

下面我们用 @contextmanager 装饰器来实现一下示例4的功能:

示例5

import sys
import contextlib

@contextlib.contextmanager
def WoHa(n):
    original_write = sys.stdout.write
    def reverse_write(text):
        original_write(text[::-1])
    sys.stdout.write = reverse_write
    yield n
    sys.stdout.write =  original_write
    return True

obj1 = WoHa('你手机拿反了')
with obj1 as content:
    print('哈哈镜花缘')
    print(content)
print('#### with 执行完毕后,在输出content: ####')
print(content)

输出:

缘花镜哈哈
了反拿机手你
#### with 执行完毕后,在输出content: ####
你手机拿反了

这里我们需要注意的是:代码执行到yield时,会产出一个值,这个值会绑定到 with 语句中 as 子句的变量上。执行 with 块中的代码时,这个函数会在yield这里暂停。此时,相当于示例4中执行完__enter__方法。而控制权一旦跳出 with 块(块内代码执行完毕)则继续执行 yield 语句之后的代码。

@contextmanager 装饰器优雅且实用,把三个不同的 Python 特性结合到了一起:函数装饰器、生成器和 with 语句。

 

© 著作权归作者所有

共有 人打赏支持
粉丝 21
博文 970
码字总数 665166
作品 0
西安
我是电音之王!FLStudio学习路线图

初步认识水果音乐软件 初步认识水果音乐 终结篇 水果音乐的安装 基本面板的认识与控制 编辑菜单基本操作的认识 通道菜单的认识及基本操作 view浏览器的基本操作 控制面板的基本操作 option菜...

棋帅小七
2017/12/01
0
0
matlab绘图中legend的终极用法

matlab绘图中legend的终极用法 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %持续更新。 当前: 20100108 % %仅作笔记。 作者: keyflying % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%......

Yong_Luo
2012/07/08
0
1
scala字符串插入

scala的字符串插入,与java语言的有类似之处,都是最终用字符串变量去替代字符串中的。Scala中主要有,,三种字符串插值用法,另外还有一些高级用法,本文主要参考官网字符串插入。 s用法 f用法...

high_m
2017/11/05
0
0
[iOS]C语言知识点系列视频整理

C语言知识点系列视频 目录 C语言技术视频-01-变量的定义 C语言技术视频-02-程序分支结构(if...else) C语言技术视频-03-程序分支结构(switch) C语言技术视频-04-程序循环结构(while{}) C语言技...

浩浩老师
2015/10/13
38
0
零依赖的序列化框架--Airy

Airy 是一个简单、快速、高效、零依赖的序列化框架。 安装 Airy 可从 releases page 获取。 Quickstart 快速上手 Airy airy = new Airy(); byte[] data = airy.serialize(someBean); SomeBe...

hfhfhdg
2017/02/04
115
0
anuglarjs基础之---ng-repeat用法

Angular - ng-repeat高级用法 ng-repeat高级用法: 遍历数组: 遍历对象: key:对象的key value:对象的value | 绑定$$haskKey: 给每个item绑定唯一ID,当数组发生变化时,ID不变! </...

爱笑嘚蛋蛋
2017/08/22
0
0
android 扩展日志库--android-log

一个android平台上的扩展日志库。 用法 1.禁止/启用日志 Log.setEnabled(true); Log.setEnabled(false); 2.设置全局日志标签 Log.setTag("Android"); 3.简单使用 Log.d("test"); Log.v("te...

snowdream
2013/10/08
2.5K
0
Linux 结构化命令(while/if/for)

Linux 结构化命令(while/if/for) 命令for两种情况针对数字和文本 针对文本: #!/bin/bash countips str="sad das asd"for s in $strdoecho $sdon 针对数字: #!/bin/bash countips for((i=...

年少爱追梦
2016/04/30
48
0
原生 Javascript 动画引擎--KUTE.js

KUTE.js 是一个原生的 Javascript 动画引擎,具有优秀的性能和模块化的代码。 它提供了一大堆工具,以帮助你创建自定义动画。 KUTE.js 为 Web 开发人员、设计师和动画师提供最基本的功能,提...

匿名
2017/01/17
412
0
MongoDB基本用法(增删改高级查询、mapreduce)

MongoDB基本用法(增删改高级查询、mapreduce) 博客分类: SQL/NOSQL 分享一下我经常用到的自己写的mongo用法示例 该示例基于当前最新的mongo驱动,版本为mongo-2.10.1.jar,用junit写的单元...

今幕明
2015/06/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java设计模式学习之工厂模式

在Java(或者叫做面向对象语言)的世界中,工厂模式被广泛应用于项目中,也许你并没有听说过,不过也许你已经在使用了。 简单来说,工厂模式的出现源于增加程序序的可扩展性,降低耦合度。之...

路小磊
21分钟前
0
0
npm profile 新功能介绍

转载地址 npm profile 新功能介绍 npm新版本新推来一个功能,npm profile,这个可以更改自己简介信息的命令,以后可以不用去登录网站来修改自己的简介了 具体的这个功能的支持大概是在6这个版...

durban
32分钟前
0
0
Serial2Ethernet Bi-redirection

Serial Tool Serial Tool is a utility for developing serial communications, custom protocols or device testing. You can set up bytes to send accordingly to your protocol and save......

zungyiu
38分钟前
0
0
python里求解物理学上的双弹簧质能系统

物理的模型如下: 在这个系统里有两个物体,它们的质量分别是m1和m2,被两个弹簧连接在一起,伸缩系统为k1和k2,左端固定。假定没有外力时,两个弹簧的长度为L1和L2。 由于两物体有重力,那么...

wangxuwei
53分钟前
0
0
apolloxlua 介绍

##项目介绍 apolloxlua 目前支持javascript到lua的翻译。可以在openresty和luajit里使用。这个工具分为两种模式, 一种是web模式,可以通过网页使用。另外一种是tool模式, 通常作为大规模翻...

钟元OSS
今天
0
0
Mybatis入门

简介: 定义:Mybatis是一个支持普通SQL查询、存储过程和高级映射的持久层框架。 途径:MyBatis通过XML文件或者注解的形式配置映射,实现数据库查询。 特性:动态SQL语句。 文件结构:Mybat...

霍淇滨
今天
0
0
开发技术瓶颈期,如何突破

前言 读书、学习的那些事情,以前我也陆续叨叨了不少,但总觉得 “学习方法” 就是一个永远在路上的话题。个人的能力、经验积累与习惯方法不尽相同,而且一篇文章甚至一本书都很难将学习方法...

_小迷糊
今天
0
0
安装tensorflow-XXX报错

报错: tensorflow-0.5.0-cp27-none-linux_x86_64.whl is not a supported wheel on this platform. 解决: wget https://bootstrap.pypa.io/get-pip.py sudo python2.7 get-pip.py sudo p......

Yao--靠自己
今天
0
0
JVM学习手册(一):JVM模型

一直从事JAVA开发,天天和JVM打交道,仔细想想对JVM还真的不是特别了解,实在是不应该.周六看了许多资料,也算有点心得,记录一下。 JVM内存模型分为5个区域:方法区,堆,虚拟机栈,本地方法栈,程序计...

勤奋的蚂蚁
今天
0
0
转行零基础该如何学Python?这些一定要明白!

转行零基础学Python编程开发难度大吗?从哪学起?近期很多小伙伴问我,如果自己转行学习Python,完全0基础能否学会呢?Python的难度到底有多大?今天,小编就来为大家详细解读一下这个问题。...

猫咪编程
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部