07-5 | 魔术方法之上下文管理

逸兴
逸兴
逸兴
57
文章
25
评论
2020-05-2322:41:10
评论
1962字阅读6分32秒

类的上下文管理其实就是两个魔术方法 __enter__ 和 __exit__, 负责进入和退出。

# encoding = utf-8
__author__ = "mcabana.com"


class A:
    def __init__(self):
        print('init ~~~~~~~~')

    def __enter__(self):    # 在执行 with 语句块前,对要操作的实例的操作
        return 'enter ~~~~~~~'

    def __exit__(self, exc_type, exc_val, exc_tb):  # 在执行 with 语句块后,对要操作的实例的操作。执行结束时的
        print('exit ~~~~~~~~~')
        return 'exit ~~~~~~~~~~~'


with A() as f:
    print(f)
    print('with ~~~~~~~~~~')
07-5 | 魔术方法之上下文管理
07-5 | 魔术方法之上下文管理

__enter__ 负责资源的申请工作,__exit__负责资源的释放工作。有异常影响,__exit__的释放操作不受影响,如下:

07-5 | 魔术方法之上下文管理

就算是 system.exit结束进程,__exit__依然会进行资源释放。__exit__是由with进行释放的。

对于一些不方便进行资源释放的类,可以定义 enter 和 exit 方法,使用with进行资源释放。

关于with子句

class A:
    def __init__(self):
        print('init ~~~~~~~~')

    def __enter__(self):    # 资源申请
        return 100

    def __exit__(self, exc_type, exc_val, exc_tb):  # 资源释放
        print('exit ~~~~~~~~~')


a = A()
with a as f:    # f = a.__enter__() , f 就是 __enter__ 的返回值
    print(a)
    print(f)
    print(a is f)
07-5 | 魔术方法之上下文管理

as 子句的对象 f, 其实就是前面实例的 __enter__方法的返回值,如果返回self,则 a is f

07-5 | 魔术方法之上下文管理

上下文的应用场景

  • 增强功能
    • 在代码执行的前后增加代码,以增强其功能。类似装饰器的功能
  • 资源管理
    • 打开了资源需要关闭,例如文件对象、网络连接、数据库连接等
  • 权限验证
    • 在执行代码之前,做权限的验证,在 __enter__ 中处理

上下文应用场景示例:

计算 add方法 的执行时间

# encoding = utf-8
__author__ = "www.mcabana.com"


# 计算add函数的执行时间

import time
import datetime


def add(x, y):
    time.sleep(1)
    return x + y


class Timeit:
    """
    计算函数的执行时间
    """
    def __init__(self, fn):     # fn是传入的函数,只是一个“标识符”
        self._fn = fn

    def __enter__(self):
        self.start = datetime.datetime.now()    # 记录开始时间
        return self._fn     # 返回传入的函数,

    def __exit__(self, exc_type, exc_val, exc_tb):
        delta = (datetime.datetime.now() - self.start).total_seconds()   # 结束时间 - 开始时间
        print('function <{}> took {}s'.format(self._fn.__name__, delta))


with Timeit(add) as t:
    print(t is add)     # 因为 Timeit.__enter__() 返回的是传入的add, 所以t is add
    t(3, 4)     # ==> add(3, 4)
07-5 | 魔术方法之上下文管理

contextlib.contextmanager

contextlib.contextmanager它是一个装饰器实现上下文管理,装饰一个函数,而不用像类一样实现__enter__ 和 __exit__ 方法。
对下面的函数有要求:必须有yield,也就是这个函数必须返回一个生成器,且只有yield一个值。
也就是这个装饰器接收一个生成器对象作为参数。

关于yield

函数中一旦出现yield,它就是一个生成器函数,返回生成器对象。

07-5 | 魔术方法之上下文管理

生成器函数中的return值,是生成器的最后一个元素,无法显示,所以生成器函数中一般没有return。

def foo():  # 函数中出现 yield 即为一个生成器函数,生成器函数返回一个生成器对象
    yield 1
    yield 100
    for i in range(4):
        yield i + 100
    return 10

f = foo()
print(f)

print(1, next(f))  # 1
print(2, next(f))  # 100
for i in range(4):
    print(i+3, next(f))  # 100, 101, 102, 103

print('last', next(f))  # 最后的reutrn值,是最有一个元素,无法显示
07-5 | 魔术方法之上下文管理
07-5 | 魔术方法之上下文管理

函数的上下文




https://www.hugbg.com/archives/2653.html
逸兴
  • 本文由 发表于 2020-05-2322:41:10
  • 除非特殊声明,本站文章均为原创,转载请务必保留本文链接
01-1 数据类型 基础语法

01-1 数据类型

第一章 数据类型 使用type() 函数可以查看数据类型 1.1 字符串 str 字符串是使用单引号或双引号括起来的任意文本。 比如'abc', '123'等 字符串类型 字符串类型用str表示 st...
09-5 | asyncio基本使用 并发编程

09-5 | asyncio基本使用

第一节 关于asyncio asyncio 在3.4 版本中加入到标准库, asyncio基于selector实现, 看似库, 其实是个框架, 包含异步IO, 事件循环, 协程, 任务等内容。 通过a...
09-4 | 全局解释器锁 & 多进程 & 池 并发编程

09-4 | 全局解释器锁 & 多进程 & 池

GIL CPython 在解释器进程级别有一把锁,叫做GIL,即全局解释器锁。 GIL 保证CPython进程中,只有一个线程执行字节码。甚至是在多核CPU的情况下,也只允许同时只能 有一个CPU核心...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: