如何在Python中使用socket作为上下文管理器?

时间:2013-05-27 11:43:35

标签: python sockets contextmanager

似乎很自然地做了类似的事情:

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

但Python没有为socket实现上下文管理器。我可以轻松地将它用作上下文管理器吗?如果是,如何使用它?

3 个答案:

答案 0 :(得分:72)

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()成为一个上下文管理器,即使文档没有提到它。请参阅源代码中的socket class,其中添加了__enter____exit__方法。

答案 1 :(得分:24)

套接字模块只是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

答案 2 :(得分:3)

请查看以下片段,包括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之间的术语“连接”的行为和方法的差异。