Python魔术方法之上下文管理

魔术方法
上下文管理

文件IO操作可以对文件对象使用上下文管理,使用with……as语法

with open('test') as f:
       pass

仿照上例写一个自己的类
在这里插入图片描述
提示错误

上下文管理对象
方法意义
enter进入与此对象相关的上下文,如果存在该方法,with语法会把该方法的返回值作为绑定到as子句中指定的变量上
exit退出与此对象相关的上下文
import  time
class Point:
    def __init__(self):
        print('init')
        time.sleep(2)
        print('init over')
    def __enter__(self):
        print('enter')
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')
with Point() as p:
    print('in with')
    time.sleep(2)
    print('with over')
print('end')

在这里插入图片描述
实例化对象的时候,并不会调用enter,进入with语句块调用__enter__方法,然后执行语句体,最后离开with语句块的时候,调用__exit__方法。
with可以开启一个上下文运行的环境,在执行前做一些准备工作,执行后做一些收尾工作。
注意,with并不开启一个新的作用域。

上下文管理的安全性
import  time
class Point:
    def __init__(self):
        print('init')
        time.sleep(2)
        print('init over')
    def __enter__(self):
        print('enter')
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')
with Point() as p:
    print('in with')
    raise Exception('error')
    print('with over')
print('end')

在这里插入图片描述
可以看出在enter和exit照样执行,上下文管理是安全的。

with语句
class Point:
    def __init__(self):
        print('init')
    def __enter__(self):
        print('enter')
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')
f=open('C:/Users/ASUS/PycharmProjects/untitled1/venv/质数.py')
with f as p:
    print(f)
    print(p)
    print(f is p)
    print(f == p)
p=Point()
with p as f:
    print('in with')
    print(p==f,'------------------------')
    print(p is f,'------------------------')
    print('with over')
print('end')

在这里插入图片描述
问题在于__enter__方法上,它将自己的返回值赋给f

方法的参数

__enter__方法没有其他参数
__exit__方法有3个参数
exit(self, exc_type, exc_val, exc_tb)三个参数与异常有关。
如果该上下文退出时没有异常,这3个参数都为None.
如果有异常,参数意义如下:
exc_type,异常类型
exc_value,异常的值
traceback,异常的追踪信息
__exit__方法返回一个等效True的值,则压制异常,否则,继续抛出异常

上下文应用场景

1、增强功能:在代码执行的前后增强代码,以增强其功能。类似装饰器的功能
2、资源管理:打开了资源需要关闭
3、权限验证:在执行代码之前,做权限的验证,在__enter__中处理

contextlib.contextmanager

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

import contextlib
@contextlib.contextmanager
def foo():
    print('enter')
    yield 1
    print('exit')
with foo() as f:
    print(f)

在这里插入图片描述
f接收yield语句的返回值。
上面的程序看似不错但是,增加一个异常发现并不能保证exit的执行,增加try finally

import contextlib
@contextlib.contextmanager
def foo():
    try:
        print('enter')
        yield 1
    finally:
        print('exit')
        return 1
with foo() as f:
    raise Exception()
    print(f)

在这里插入图片描述
当yield发生处为生成器函数增加了上下文管理,这是为函数增加上下文机制的方式

  • 把yield之前的当做__enter__方法执行
  • 把yield之后的当做__exit__方法执行
  • 把yield的值作为__enter__的返回值

总结:如果业务逻辑简单可以使用函数如contextlib.contextmanager装饰器方式,如果业务复杂,用类的方式如__enter__和__exit__方法方便

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值