web-dev-qa-db-ja.com

Pythonでソケットをコンテキストマネージャとして使用する方法は?

次のようなことをするのは自然なことのようです:

with socket(socket.AF_INET, socket.SOCK_DGRAM) as s:

しかし、Pythonはソケットのコンテキストマネージャーを実装していません。コンテキストマネージャーとして簡単に使用できますか。

41
ChaimKut

socketモジュールはかなり低レベルなので、Cライブラリ機能にほとんど直接アクセスできます。

いつでも _contextlib.contextmanager_ decorator を使用して独自のコードを作成できます。

_import socket
from contextlib import contextmanager

@contextmanager
def socketcontext(*args, **kw):
    s = socket.socket(*args, **kw)
    try:
        yield s
    finally:
        s.close()

with socketcontext(socket.AF_INET, socket.SOCK_DGRAM) as s:
_

または contextlib.closing() を使用して同じ効果を達成します:

_from contextlib import closing

with closing(socket.socket(socket.AF_INET, socket.SOCK_DGRAM)) as s:
_

しかし、contextmanager()デコレータは、最初にソケットで他のことを行う機会を与えます。

Python 3.xはsocket()をコンテキストマネージャーにします。 ___enter___および___exit___メソッドを追加するソースコードの socket class を参照してください。

78
Martijn Pieters

ソケットモジュールは、BSDソケットインターフェイスの単なるラッパーです。これは低レベルであり、Pythonic APIを使用するための便利な、または使いやすいものを提供しようとするものではありません。より高いレベルのものを使用することもできます。

とはいえ、実際にはコンテキストマネージャーを実装しています:

>>> with socket.socket() as s:
...   print(s)
... 
<socket.socket object, fd=3, family=2, type=1, proto=0>

ただし、Python 3.を使用する必要があります。

Python 2との互換性のために、contextlibを使用できます。

from contextlib import closing
import socket

with closing(socket.socket()) as s:
    print s
25
Lennart Regebro

TCPとUDPソケットの両方について、以下のスニペットをご覧ください。

import socket
from contextlib import contextmanager


@contextmanager
def tcp_connection_to(*args, **kwargs):
    s = socket.create_connection(*args, **kwargs)
    yield s
    s.close()


@contextmanager
def udp_connection():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    yield s
    s.close()

したがって、次のように使用できます。

MY_SERVER = ('localhost', 5000)   # Yes, we need Tuple here
some_data = bytes("Hello.")

with tcp_connection_to(MY_SERVER) as conn:
    conn.send(some_data)

with udp_connection() as conn:
    conn.sendto(some_data, MY_SERVER)

メソッド名のTCPとUDPの間の動作と用語「接続」へのアプローチの違いを強調しようとしました。

3
mieciu