PYTHON对象支持上下文管理器

通过with触发的上下问管理协议的运行机制

with是我们常用的上下文管理运行机制,今天这篇博文主要用于理解上下文管理协议的运行机制,了解其机制后方便我们自己查看他人代码。

如何让对象可以兼容with语句

让一个python中的class可以支持with语句,必须要在其class中实现如下两个方法__enter__()与__exit__()两个方法。示例代码如下:
from socket import socket ,AF_INET,SOCK_STREAM
class LazyConnection:

def __init__(self,address,family=AF_INET,type=SOCK_STREAM):
    self.address=address
    self.family=AF_INET
    self.type=SOCK_STREAM
    self.sock=None

def __enter__(self):
    if self.sock is not None:
        raise RuntimeError ("Already connected!!!")
    self.sock=socket(self.family,self.type)
    self.sock.connect(self.address)
    return self.sock

def __exit__(self, exc_type, exc_val, exc_tb):
    self.sock.close()
    self.sock=None

这个类的核心功能表示建立一条网络连接,但在初始状态下,它不会有任何动作,而是通过with开始建立网络连接的
代码实现如下:

from  functools  import partial    
conn=LazyConnection(('www.python.org',80))

with conn as s:
    s.send(b'GET /index.html HTTP/1.0\r\n')
    s.send(b'Host:www.python.org\r\n')
    s.send(b'\r\n')
    resp=b''.join(iter(partial(s.recv,8192),b''))
    print(resp)

当我们遇到一个with语句时,__enter__方法首先被执行,若__enter__方法中有返回值,则放置在as限定的变量中;之后开始执行with代码块中的其他内容,最后,exit__方法被触发来执行清理工作。
其中,exit()方法中的三个参数用于处理异常,包含异常类型、值、和对挂起异常的追溯。
exit()方法可以选择以某种方式来使用异常信息;但是,也可以什么都不做或干掉异常,返回None作为结果,**如果__exit
()方法返回了True作为结果,则异常会被清理干净,就好像什么也没有发生一样。**

讨论

以上代码如果重复使用socket连接,代码就会产生异常,如果我们需要嵌套此socket连接应该如下形式实现
from socket import socket ,AF_INET,SOCK_STREAM

class LazyConnection:
    def __init__(self,address,family=AF_INET,type=SOCK_STREAM):
        self.address=address
        self.family=AF_INET
        self.type=SOCK_STREAM
        #self.sock=None
        self.connections=[]
    def __enter__(self):
        sock=socket(self.family,self.type)
        sock.connect(self.address)
        self.connections.append(sock)
        return sock

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.connections.pop().close()
        self.sock=None


from  functools  import partial

conn=LazyConnection(('www.python.org',80))

with conn as s1:
   ...
    with conn as s2:
        ...

第二个版本中,LazyConnection成为了一个专门生产网络连接的工厂类。内部实现中,我们把connections列表当作一个栈来使用,用于存储和保存连接。enter()开始执行时,会把新建连接存储于connections中,而__exit__()方法只会把最后一个新建的连接结束。

总结

上下文管理器最常用于管理类似文件、网络连接和锁这样的资源。这些资源全部有一个共同的特点,必须显示的进行关闭或释放才可以正常工作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值