[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
语句。
参考:让对象支持上下文管理协议