Loading

[Coding笔记] Python上下文管理协议

在python中,支持了上下文管理协议的对象可以使用在with ... as ...语句中,如:

with open("a.txt") as file_pipline:
    ...

为了让一个对象兼容 with 语句,我们需要实现__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 = family
        self.type = type
        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_ty, exc_val, tb):
        self.sock.close()
        self.sock = None

当出现 with 语句的时候,对象的 __enter__() 方法被触发, 它返回的值(如果有的话)会被赋值给 as 声明的变量。然后,with 语句块里面的代码开始执行。 最后,__exit__() 方法被触发进行清理工作。

不管 with 代码块中发生什么,上面的控制流都会执行完,就算代码块中发生了异常也是一样的。 事实上,__exit__() 方法的第三个参数包含了异常类型、异常值和追溯信息(如果有的话)。 __exit__() 方法能自己决定怎样利用这个异常信息,或者忽略它并返回一个None值。 如果 __exit__() 返回 True ,那么异常会被清空,就好像什么都没发生一样, with 语句后面的程序继续在正常执行。


在项目实践中的代码实例:

class SSHConnector:
    def __init__(self, ip):
        self.ip = ip
        ...

    def __enter__(self):
        ssh = paramiko.SSHClient()
        ...
        self.ssh = ssh
        return ControlInstance(ssh)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.ssh.close()
        if exc_type:
            # 错误类型,错误值,错误追溯信息,无错误时默认为None
            print(exc_type, exc_val, exc_tb)

class ControlInstance:
    def __init__(self, ssh):
        self.ssh = ssh

    def execute(self, command):
        stdin, stdout, stderr = self.ssh.exec_command(command)
        result = bytes.decode(stdout.read())
        return result

这段代码用来创建一个SSH连接,在类中通过实现上下文管理协议使其支持with语句。

参考:让对象支持上下文管理协议

posted @ 2019-11-26 13:35  云野Winfield  阅读(166)  评论(0编辑  收藏  举报