【1.135】__enter__和__exit__方法 上下文管理协议

上下文管理协议,即with语句,

为了让一个对象兼容with语句,

必须在这个对象的类中声明__enter__和__exit__方法

class Foo:
    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 中的语句执行完以后执行exit")


with Foo("b.txt") as f1:
    print ("=======>")
    print(f1)
    print(f1.name)
    print("=======>")


# 出现with语句,对象的__enter__被触发,有返回值,就赋值给 as 后声明的变量
# =======>
# <__main__.Foo object at 0x00000000022061D0>
# b.txt
# =======>
# with 中的语句执行完以后执行exit
#b.txt文件与该文件 在同一个文件夹中

 

 

__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,

with语句中代码块出现异常,则with后的   所有代码   都无法执行,

若果没有错误,那么这三个值就None

如果exit  返回值 为 true  那么:exit 中的异常获取三元素 就被忽略,

with模块 后面的语句照样执行,就当什么也没有发生

class Foo:
    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 中的语句执行完以后执行exit")
        print("错误类型",exc_type)
        print("错误值",exc_val)
        print("错误追踪信息",exc_tb)


with Foo("b.txt") as f1:
    print ("=======>")
    print(f1)
    print(f1.name)
    raise AttributeError("WITH中出错了。。。。。")
    print("=======>")
print("我就是来看热闹的,你没有错误我就出来")


# 出现with语句,对象的__enter__被触发,有返回值,就赋值给 as 后声明的变量
# =======>
# <__main__.Foo object at 0x00000000021E61D0>
# b.txt
# with 中的语句执行完以后执行exit
# 错误类型 <class 'AttributeError'>
# 错误值 WITH中出错了。。。。。
# 错误追踪信息 <traceback object at 0x00000000021DE0C8>

若果没有错误,那么这三个值就None

class Foo:
    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 中的语句执行完以后执行exit")
        print("错误类型",exc_type)
        print("错误值",exc_val)
        print("错误追踪信息",exc_tb)


with Foo("b.txt") as f1:
    print ("=======>")
    print(f1)
    print(f1.name)
    # raise AttributeError("WITH中出错了。。。。。")
    print("=======>")
print("我就是来看热闹的,你没有错误我就出来")



# 出现with语句,对象的__enter__被触发,有返回值,就赋值给 as 后声明的变量
# =======>
# <__main__.Foo object at 0x00000000023E61D0>
# b.txt
# =======>
# with 中的语句执行完以后执行exit
# 错误类型 None
# 错误值 None
# 错误追踪信息 None
# 我就是来看热闹的,你没有错误我就出来

如果exit  返回值 为 true  那么:exit 中的异常获取三元素 就被忽略,

with模块,后面的语句照样执行,就当什么也没有发生

class Foo:
    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 中的语句执行完以后执行exit")
        print("错误类型",exc_type)
        print("错误值",exc_val)
        print("错误追踪信息",exc_tb)
        return True


with Foo("b.txt") as f1:
    print ("=======>")
    print(f1)
    print(f1.name)
    raise AttributeError("WITH中出错了。。。。。")
    print("=======>")
print("我就是来看热闹的,你没有错误我就出来")


# 出现with语句,对象的__enter__被触发,有返回值,就赋值给 as 后声明的变量
# =======>
# <__main__.Foo object at 0x0000000001E86198>
# b.txt
# with 中的语句执行完以后执行exit
# 错误类型 <class 'AttributeError'>
# 错误值 WITH中出错了。。。。。
# 错误追踪信息 <traceback object at 0x0000000001E7AF48>
# 我就是来看热闹的,你没有错误我就出来

 

看看 如何模拟 with 语句打开 open,利用上下文管理协议

用途或者说好处:

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

2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,

可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处

class Open:
    def __init__(self,file,mode="r",encoding="UTF-8"):
        self.file = file
        self.mode = mode
        self.enconding = encoding
    def __enter__(self):
        self.f=open(self.file,mode=self.mode,encoding=self.enconding)   #如果没有定义,默认就open中的功能
        return self.f
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()
        return True
    def __getattr__(self, item):   #定义了读
        print(item)
        return getattr(self.f,item)

with Open("b.txt","w+",encoding="utf-8") as f1:
    print(f1)
    f1.write("--231--dasfdfa----")   # 只定义了读,其他就用open默认定义的功能
    # f1.sdfadfa   #抛出错误,交给exit来处理,如果运行这句,那下面所有代码都不能运行
    f1.seek(0)                      # 只定义了读,其他就用open默认定义的功能
    a=f1.read(3)                    # 使用了定义的读  getattr
    print(a)

 

posted @ 2019-07-04 16:43  科学小怪癖  阅读(84)  评论(0)    收藏  举报