本文共 4012 字,大约阅读时间需要 13 分钟。
自己写一下Python的with语句实现
第一种方法利用魔法方法__enter__和__exit__实现:
顾名思义__enter__是打开上文,__exit__关闭下文,相当于打开文件、关闭文件。
#coding=gbk#第一种,魔法方法实现方法class WithContext(): def __init__(self,name=None): print('接收参数:%r'%name) self.name=name def with_context(self): print(self.name) print('调用with方法') def __enter__(self): print('调用enter方法') return self def __exit__(self, exc_type, exc_val, exc_tb): print('调用exit方法')if __name__ == '__main__': # 'test_with'作为参数传递给__init__方法 #w为__enter__方法的返回值 with WithContext('test_with') as w: print('with语句返回值:%r'%w) print('with语句返回值类型:%r'%type(w)) print(w.name) w.with_context()
执行结果:
接收参数:'test_with'
调用enter方法 with语句返回值:<__main__.WithContext object at 0x00000000010B98D0> with语句返回值类型:<class '__main__.WithContext'> test_with test_with 调用with方法 调用exit方法
'test_with'作为参数传递给__init__方法 w为__enter__方法的返回值
可以看出各个方法的执行顺序:
__init__
__exit__
with_context
__exit__
with语句中的__enter__无返回值的情况:
#coding=gbk#第一种,魔法方法实现方法class WithContext(object): def __new__(cls,*args,**kwargs): if not hasattr(cls,'_instance'): cls._instance=super().__new__(cls) cls._instance.name='test_with' return cls._instance def __init__(self,name=None): self.name=name print('接收参数:%r'%name) def with_context(self): print(self.name) print('调用with方法') def __enter__(self): print('调用enter方法') def __exit__(self, exc_type, exc_val, exc_tb): print('调用exit方法')if __name__ == '__main__': # 'test_with'作为参数传递给__init__方法 #w为__enter__方法的返回值 with WithContext('test_with') as w: print('with语句返回值:%r'%w) print('with语句返回值类型:%r'%type(w))
运行结果:
接收参数:'test_with'
调用enter方法 with语句返回值:None with语句返回值类型:<class 'NoneType'> 调用exit方法
顺便说下__exit__方法中的这个三个参数‘exc_type, exc_val, exc_tb’,
异常类型,异常值和异常的trackback
如果with语发生异常,但不希望抛出,__exit__方法应该返回return True,相当于with语句自动做一个try,except处理,
class WithContext(object): def __init__(self,name=None): self.name=name print('接收参数:%r'%name) def with_context(self): print(self.name) print('调用with方法') def __enter__(self): print('调用enter方法') return self def __exit__(self, exc_type, exc_val, exc_tb): print(exc_type, exc_val, exc_tb) print('调用exit方法') return True #return Trueif __name__ == '__main__': # 'test_with'作为参数传递给__init__方法 #w为__enter__方法的返回值 with WithContext('test_with') as w: #发生异常 a=1/0 #a=1/0 pass
执行结果:
虽然发生异常,但是并没有报错。
接收参数:'test_with'
调用enter方法 <class 'ZeroDivisionError'> division by zero <traceback object at 0x0000000000BAE548> 调用exit方法
如果把return True注释掉,
结果如下:
抛出了异常,打印出了trackback
Traceback (most recent call last):
接收参数:'test_with' 调用enter方法 File "C:/Users/wangjinyu/PycharmProjects/work_practice/p_103_with_context.py", line 49, in <module> <class 'ZeroDivisionError'> division by zero <traceback object at 0x000000000081E548> a=1/0 调用exit方法 ZeroDivisionError: division by zero
如果把a=1/0注释掉,换成pass,exc_type, exc_val, exc_tb的值均为None
输出结果:
接收参数:'test_with'
调用enter方法 None None None 调用exit方法
参考:
官方文档:
object.
__exit__
(self, exc_type, exc_value, traceback)Exit the runtime context related to this object. The parameters describe the exception that caused the context to be exited. If the context was exited without an exception, all three arguments will be .
If an exception is supplied, and the method wishes to suppress the exception (i.e., prevent it from being propagated), it should return a true value. Otherwise, the exception will be processed normally upon exit from this method.
Note that methods should not reraise the passed-in exception; this is the caller’s responsibility.
blog:
第二种方法,用装饰器实现,百度后简单试了下,其实就是利用yield关键字的生成器实现
import contextlib@contextlib.contextmanagerdef with_context(a): print('执行前') res=a*a yield res print('执行后')if __name__ == '__main__': #f就是yield 的返回值res #参数2实参,传递给形参a with with_context(2) as f: print(f*f)
执行结果:
执行前
16 执行后
转载地址:http://icxws.baihongyu.com/