zoukankan      html  css  js  c++  java
  • python中的with的用法,上下文管理器

     

    with是从Python2.5引入的一个新的语法,它是一种上下文管理协议,目的在于从流程图中把 try,except 和finally 关键字和

     

    资源分配释放相关代码统统去掉,简化try….except….finlally的处理流程。

     

    with通过__enter__方法初始化,然后在__exit__中做善后以及处理异常。

     

    所以使用with处理的对象必须有__enter__()和__exit__()这两个方法。

     

    其中__enter__()方法在语句体(with语句包裹起来的代码块)执行之前进入运行,__exit__()方法在语句体执行完毕退出后运行。

     

    with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。

     

     

    首先来看一段代码:

    复制代码
    class Foo(object):
    
        def __init__(self):
            print('实例化一个对象')
    
        def __enter__(self):
            print('进入')

    def __exit__(self, exc_type, exc_val, exc_tb): print('退出') obj = Foo() with obj: print('正在执行')
    复制代码

    上面代码执行结果为:

    实例化一个对象
    进入
    正在执行
    退出

    结论1

    我们知道,实例化Foo,得到obj对象,会执行Foo的__init__方法,也就是打印了第一句;

    按照,程序从上至下执行,应该会打印“正在执行”才对,为什么会在它之前先打印了进入,在它之后打印了退出呢?

    因为我们在定义Foo时,定义了__enter__和__exit__方法,那么我们实例化的对象obj就是一个上下文管理器,

    含有__enter__和__exit__方法的对象就是上下文管理器

    with 上下文管理器:
         语句体

       当with遇到上下文管理器,就会在执行语句体之前,先执行上下文管理器的__enter__方法,然后再执行语句体,执行完语句体后,最后执行__exit__方法

    这也就是为什么会出现文章开头的情况的原因。

    再看看这段代码:

    复制代码
    class Foo(object):
    
        def __init__(self):
            print('实例化一个对象')
    
        def __enter__(self):
            print('进入')
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('退出')
         # return True obj = Foo() with obj: raise ImportError print('正在执行')
    复制代码

    结果如下:

     把上面代码中我们注释掉的那一行代码取消注释,结果如下

     我们会发现,虽然我们故意在语句体中抛出一个错误,按照正常情况,执行到报错地方就不会执行了,而__exit__是在语句体执行完之后执行的,但还是执行了__exit__方法;当我们在__exit__中给一个返回值为Ture时,就会忽略错误

    结论2

    所有我们可以发现

    with语句类似

      try :

      except:

      finally:

    的功能:但是with语句更简洁。而且更安全。代码量更少。

       出现异常时,如果 __exit__ 返回 False(默认不写返回值时,即为False),则会重新抛出异常,让with 之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对异常进行处理

     
    复制代码
    class Foo(object):
    
        def __init__(self):
            print('实例化一个对象')
    
        def __enter__(self):
            print('进入')
            # return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('退出')
    
    
    with Foo() as obj:
        print(obj,type(obj))
        print('正在执行')
    复制代码

    把上面代码中我们注释掉的那一行代码取消注释,结果如下

    结论

    调用上下文管理器的 __enter__ 方法时;如果使用了 as 子句,则将 __enter__() 方法的返回值赋值给 as 子句中的目标

    with 上下文管理器  as  target:
        代码语句体

      with后面必须跟一个上下文管理器,如果使用了as,则是把上下文管理器的 __enter__() 方法的返回值赋值给 target,target 可以是单个变量,或者由“()”括起来的元组(不能是仅仅由“,”分隔的变量列表,必须加“()”)

     

    我们经常会看到这样的代码:

    with open("/tmp/foo.txt") as file:
        data = file.read()

     结论

    这里使用了 with 语句,不管在处理文件过程中是否发生异常,都能保证 with 语句执行完毕后已经关闭了打开的文件句柄。如果使用传统的 try/finally 范式,则要使用类似如下代码:

    复制代码
    somefile = open(r'somefileName')
    try:
        for line in somefile:
            print line
            # ...more code
    finally:
        somefile.close()
    复制代码

    比较起来,使用 with 语句可以减少编码量。已经加入对上下文管理协议支持的还有模块 threading、decimal 等。

    with只能配合上下文管理器使用,常见的上下文管理器有

    复制代码
    file
    decimal.Context
    thread.LockType
    threading.Lock
    threading.RLock
    threading.Condition
    threading.Semaphore
    threading.BoundedSemaphore


    转载:https://www.cnblogs.com/huchong/p/8268765.html
  • 相关阅读:
    java+opencv实现图像灰度化
    java实现高斯平滑
    hdu 3415 单调队列
    POJ 3368 Frequent values 线段树区间合并
    UVA 11795 Mega Man's Mission 状态DP
    UVA 11552 Fewest Flops DP
    UVA 10534 Wavio Sequence DP LIS
    UVA 1424 uvalive 4256 Salesmen 简单DP
    UVA 1099 uvalive 4794 Sharing Chocolate 状态DP
    UVA 1169uvalive 3983 Robotruck 单调队列优化DP
  • 原文地址:https://www.cnblogs.com/coxiseed/p/11619419.html
Copyright © 2011-2022 走看看