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
  • 相关阅读:
    C++使用GDI+实现图片格式转换
    易语言调用C++写的DLL
    【PE】手动给PE文件添加一段代码MessageBoxA
    SHGetSpecialFolderLocation获取开始文件夹
    MySQL导入导出数据
    MySQL5.7修改密码
    Elasticsearch 基于external的乐观锁的版本控制
    Elasticsearch修改字段类型 (_reindex)
    es 迁移数据, 重建索引
    SHELL
  • 原文地址:https://www.cnblogs.com/coxiseed/p/11619419.html
Copyright © 2011-2022 走看看