Python魔术方法之上下文管理

    xiaoxiao2023-11-11  167

    魔术方法

    上下文管理

    文件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)