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__()
メソッドは、これらの を する がないからです.