pythonクラスサポートwith呼び出し

4103 ワード

enter exit
オブジェクトを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 を して に します.たとえば、 のようになります.
from functools import partial 
 

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

Connection closed

with conn as s:
# conn.enter() executes: connection open
s.send(b'GET /index.html HTTP/1.0\r
')
s.send(b'Host: www.python.org\r
')
s.send(b'\r
')
resp = b''.join(iter(partial(s.recv, 8192), b''))
# conn.exit() executes: connection closed


ディスカッション
コンテキストマネージャを する な は、コードがwith ブロックに されて されることです.with が されると、オブジェクトの__enter__()メソッドがトリガーされ、その される ( する )はas に り てられます.その 、with ブロック のコードが される. に、__exit__()メソッドは、クリーンアップ をトリガする.withコードブロックで が こっても、 の フローは され、コードブロックに が しても じです. 、__exit__()メソッドの3 のパラメータには、 タイプ、 、およびトレーサビリティ ( する )が まれます.__exit__()メソッドは、この をどのように するかを で したり、 してNone を したりすることができます.__exit__()Trueを すと、 はクリアされ、 も こらないようにwith の のプログラムは に されます.
もう1つの な は、LazyConnectionクラスが のwith をネストして を することを するかどうかです. らかに、 の では に1つのsocket しか されず、1つのsocketを している にwith を り し すると、 が します.しかし、 のように の を してこの を することができます.
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.connections = []

def __enter__(self):
    sock = socket(self.family, self.type)
    sock.connect(self.address)
    self.connections.append(sock)
    return sock

def __exit__(self, exc_ty, exc_val, tb):
    self.connections.pop().close()

Example use
from functools import partial
conn = LazyConnection(('www.python.org', 80)) with conn as s1: pass with conn as s2: pass # s1 and s2 are independent sockets
2のバージョンでは、LazyConnectionクラスは、ある と なすことができる. では、スタックを するためにリストが されます.__enter__()メソッドが されるたびに、 しい を し、スタックに します.__exit__()メソッドは、スタックから の を にポップアップし、 じます.ここでは し かりにくいですが、 で したように、ネストはwith を して の を することができます.
ファイル、ネットワーク 、ロックなどのリソースを するプログラミング では、コンテキストマネージャを するのが です.これらのリソースの な は、プログラムの しい を するために で じたり したりしなければならないことです.たとえば、ロックを した は、 で されたことを する があります.そうしないと、デッドロックが する があります.__enter__()メソッドと__exit__()メソッドを し、with を することで、これらの を に できます.__exit__()メソッドは、これらの を する がないからです.