美文网首页
python中的with关键字

python中的with关键字

作者: 222AblackA | 来源:发表于2019-08-10 21:47 被阅读0次

python中的with关键字

文件、数据库连接、socket、线程、进程等系统资源,应用程序打开这些资源并执行完业务逻辑后,必须释放这些资源,可以通过资源对象的close()或其他方法关闭资源,但是比较繁琐,开发中也容易忘记关闭资源,with关键字对资源管理提供了方便

a. 文件的打开,关闭:

def open_file_close():
    f = open('test.txt','r')   # 当然,也可以写try/except/finally在finally中关闭资源
    data = f.read()
    f.close()

但是并没有用with关键字更加优雅简洁、更加方便:

def with_file():
    with open('test.txt','r') as f:
        data = f.read()
with语句会自动打开文件,并将对象以f别名返回,在处理完后,自动关闭资源

b. with的实现原理(上下文管理器):

任何实现了_enter_()和_exit_()方法的对象都可以称之为上下文管理器,任何对象,只要正确实现了上下文管理,就可以使用with来进行管理

当一个对象的父类中定义了__enter__()和__exit__()方法,就可以用with关键字来进行该对象的资源管理
with关键字首先会寻找资源对象父类中是否有__enter__()和__exit__()方法,如果有则会调用__enter__()
方法,__enter__()方法一般都是打开资源返回资源对象,当with下的业务逻辑处理完,就会自动调用__exit__()方法
方法,一般处理一些释放资源的清除工作,当我们要自定义一个上下文管理器,用with进行管理时,编写
__enter__()必须要有返回值,编写__exit__()方法传入的参数必须是4个(包括self),如果__exit__()
方法返回True,表示with-body中的代码出现异常时,忽略异常继续执行,返回False向上层抛异常

c. with实现线程锁资源的管理

import threading
import time
num = 0
mutex=threading.Lock()
class Mythread(threading.Thread):  # 生成线程类
    def run(self):
        global num
        with mutex:   #  用with关键字实现锁的自动添加和自动释放,代替锁的acquire()和release()方法
          for i in range(100):
             num+=1
        print(num)
my_list = []
for i in range(5):
   t = Mythread()
   t.start()
   mythread.append(t)
for t in mythread:
   t.join()
print('finished')

d. 自定义资源管理器类(可以用with进行管理)

class A():
    def __enter__(self):
        self.a=1
        return self
    def f(self):
        print('f')
    def __exit__(self,a,b,c):
        print('exit')

with A() as a:
    1/0     # 当with下的代码有异常时,如果__exit__()返回True,程序忽略错误,执行__exit__()中的代码
            # 如果__exit__()返回False,会抛出错误执行__exit__()方法,终止程序(但with并不能捕捉错误)
    a.f()
    print(a.a)

e. contextlib模块(让对象实现上下文管理器来支持with)

contextlib模块提供了三个对象:contextmanager装饰器,nested函数和上下文管理器closing,可以对已有的生成器函数或者对象进行包装,加入上下文管理协议来支持with语句

one -- 装饰器contextmanager --

@contextmanager让我们通过编写generator生成器函数来简化上下文管理,可以实现执行一段代码之前做一些业务逻辑,在
执行这段代码之后,再执行一些业务逻辑的功能

用于对生成器函数进行装饰返回一个上下文管理器,它的__enter__()和__exit()__方法由contextmanager负
责提供,被装饰的生成器只能返回一个值(yield关键字后面只有一个返回值),否则会导致异常,产生的值会赋
值给as子句中的target变量(如果使用了as子句)

            from contextlib import contextmanager
            @contextmanager
            def tag(name):
                print("<%s>" % name)
                yield
                print("</%s>" % name)
            
            with tag("h1") as f:
                print(f)
                print("hello")
                print("world")

        以上代码的执行顺序是:
        1. with语句首先执行yield之前的语句,因此打印出<h1>;
        2. yield调用会执行with语句内部的所有语句,因此打印f的值,由于yield没有返回值,
           则会打印None,再打印hello和world;
        3. 最后执行yield之后的语句,打印出</h1>。
two -- nested()函数 --

将多个上下文管理器组织到一起,避免with的嵌套

注意: 如果发生异常,某个上下文管理器的 _exit_() 方法对异常处理返回 False,上层管理器监测不到异常
则更外层的上下文管理器不会监测到异常

    比如以下代码:
    with nested(A(), B(), C()) as (X, Y, Z):
         print('ABC')

    等价于:
    with A() as X:
        with B() as Y:
            with C() as Z:
                 print('ABC')
three -- closing上下文管理器

closing适用于有close()方法的对象(否则会报AttributeError 错误),比如网络连接、数据库连接等,通过接口close()来执行所需要的资源“清理”工作

class ClosingDemo(object):
    def __init__(self):
        self.acquire()
    def acquire(self):
        print('init 调用')
    def free(self):
        print('close调用')
    def close(self):
        self.free()
 
with closing(ClosingDemo()):
    print('with_body执行')
    
执行结果:
init 调用
with_body执行
close调用

相关文章

网友评论

      本文标题:python中的with关键字

      本文链接:https://www.haomeiwen.com/subject/hiedjctx.html