Ptyhon使用技巧--上下文管理协议with语句

我们知道在操作文件对象的时候可以这么写

with open('a.txt') as f:
   '代码块'

 上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法

class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
        # return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')


with Open('a.txt') as f:
    print('=====>执行代码块')

输出:

出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
=====>执行代码块
with中代码块执行完毕时执行我啊

 

__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行

class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行__exit__')
        print(exc_type)
        print(exc_val)
        print(exc_tb)



with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('***着火啦,救火啊***')
    print('aaaaaaaaa') #不会执行
print('0'*100) #------------------------------->不会执行
 

输出:

出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
=====>执行代码块
with中代码块执行完毕时执行__exit__
<type 'exceptions.AttributeError'>
***着火啦,救火啊***
<traceback object at 0x0000000002BB2208> Traceback (most recent call last): File "D:/PythonProject/testProject/with_test.py", line 21, in <module> raise AttributeError('***着火啦,救火啊***') AttributeError: ***着火啦,救火啊***

 

 如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行

class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行__exit__')
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        return True


with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('***着火啦,救火啊***')
    print('aaaaaaaaa') #不会执行
print('0'*100) #------------------------------->会执行

输出:

出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
=====>执行代码块
with中代码块执行完毕时执行__exit__
<type 'exceptions.AttributeError'>
***着火啦,救火啊***
<traceback object at 0x0000000002A72208>
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

 

 

class Open:
    def __init__(self,filepath,mode='r',encoding='utf-8'):
        self.filepath=filepath
        self.mode=mode
        self.encoding=encoding

    def __enter__(self):
        # print('enter')
        self.f=open(self.filepath,mode=self.mode,encoding=self.encoding)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        # print('exit')
        self.f.close()
        return True 
    def __getattr__(self, item):
        return getattr(self.f,item)

with Open('a.txt','w') as f:
    print(f)
    f.write('aaaaaa')
    f.wasdf #抛出异常,交给__exit__处理

用途或者说好处:

1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预

2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关心这个问题,这将大有用处

with语句的应用

1.用 with open()语句可以不用手动关闭文件流,其实也运用了上下文管理协议(器)。

with open('a.txt') as f:
   '代码块'

 执行with open('a.txt') as f,会调用上下文管理器的__entet__()方法,执行完代码块之后执行__exit__()方法,即使代码出现异常也会运行‘清理’代码。

 

2.用with语句进行锁的操作

from threading import Lock

lock = Lock()
with  lock:
    print "Lock is held"

 

 上面的操作,相当于以下操作

lock.acquire()
try:
    print('Lock is held')
finally:
    lock.release()

 

最后,如果我们不想定义新的类,并提供名为__enter__和__exit__的特殊方法,那么可以使用con

 

posted on 2019-05-11 16:40  xufat  阅读(232)  评论(0)    收藏  举报

导航

/* 返回顶部代码 */ TOP