2025-09-10:仓库迁移
This commit is contained in:
58
8.类与对象/3.让对象支持上下文管理协议.py
Normal file
58
8.类与对象/3.让对象支持上下文管理协议.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# 有时候我们想让类支持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
|
||||
self.sock = socket(self.family, self.type)
|
||||
self.sock.connect(self.address)
|
||||
print("链接被拉起")
|
||||
return self.sock
|
||||
|
||||
def __exit__(self, exc_ty, exc_va, tb):
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
print("链接关闭")
|
||||
|
||||
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, 1024), b''))
|
||||
# 链接被关闭
|
||||
|
||||
# 但是这个类只能使用单层的with,如果有多个with嵌套,它就会失效
|
||||
# 可以对原来的类进行一次修改,做一个工厂类,每次从一个栈中存取一个链接
|
||||
class LazyConnectionV2():
|
||||
def __init__(self, address, family=AF_INET, type=SOCK_STREAM):
|
||||
self.address = address
|
||||
self.family = family
|
||||
self.type = type
|
||||
# 单个的sock被替换成空列表
|
||||
self.connections = []
|
||||
|
||||
def __enter__(self):
|
||||
# 建立一个socket链接
|
||||
sock = socket(self.family, self.type)
|
||||
sock.connect(self.address)
|
||||
# 将链接压入栈中
|
||||
self.connections.append(sock)
|
||||
print("链接被拉起")
|
||||
return sock
|
||||
|
||||
def __exit__(self, exc_ty, exc_va, tb):
|
||||
# 将最近被压入栈的链接弹出并关闭
|
||||
self.connections.pop().close()
|
||||
print("链接关闭")
|
Reference in New Issue
Block a user