web-dev-qa-db-fra.com

Comment utiliser socket dans Python comme gestionnaire de contexte?

Il semble qu'il serait naturel de faire quelque chose comme:

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

mais Python n'implémente pas de gestionnaire de contexte pour socket. Puis-je facilement l'utiliser comme gestionnaire de contexte, et si oui, comment?

41
ChaimKut

Le module socket est assez bas niveau, vous donnant un accès presque direct à la fonctionnalité de la bibliothèque C.

Vous pouvez toujours utiliser le décorateur contextlib.contextmanager pour créer le vôtre:

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:

ou utilisez contextlib.closing() pour obtenir le même effet:

from contextlib import closing

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

mais le décorateur contextmanager() vous donne la possibilité de faire d'autres choses avec le socket en premier.

Python 3.x fait de socket() un gestionnaire de contexte, même si la documentation ne le mentionne pas. Voir la classe socket dans le code source, qui ajoute les méthodes __enter__ Et __exit__.

78
Martijn Pieters

Le module socket est juste un wrapper autour de l'interface socket BSD. Il est de bas niveau et n'essaie pas vraiment de vous fournir une API Pythonic pratique ou facile à utiliser. Vous voudrez peut-être utiliser quelque chose de niveau supérieur.

Cela dit, il implémente en fait un gestionnaire de contexte:

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

Mais vous devez utiliser Python 3.

Pour la compatibilité Python 2, vous pouvez utiliser contextlib.

from contextlib import closing
import socket

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

Veuillez consulter les extraits suivants, pour les deux TCP et sockets 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()

Pour que vous puissiez les utiliser de la manière suivante:

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)

J'ai également essayé de souligner la différence de comportement et d'approche du terme "connexion" entre TCP et UDP dans les noms de méthode.

3
mieciu