python `с оператором .. as ..` и несколькими возвращаемыми значениями

Я пытаюсь использовать оператор python with (также известный как менеджер контекста), чтобы гарантировать, что сокет соединения TCP, созданный server_socket.accept(), всегда закрыт. Однако очевидная форма не работает, потому что accept() возвращает несколько значений.

Есть ли способ использовать оператор with для функций с несколькими возвращаемыми значениями?

Минимальный пример приведен ниже, я хочу использовать что-то вроде закомментированного кода, чтобы заменить блок try/finally.

#!/usr/bin/env python3

import socket
from socket import socket as Socket

with Socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:

        server_socket.bind(('', 8011))
        server_socket.listen(1)
        print("server ready")

        while True:

            # with server_socket.accept() as (connection_socket, _):
            #     request = connection_socket.recv(1024).decode('ascii')
            #     reply = request.upper()
            #     connection_socket.send(reply.encode('ascii'))

            try:
                connection_socket, _ = server_socket.accept()
                request = connection_socket.recv(1024).decode('ascii')
                reply = request.upper()
                connection_socket.send(reply.encode('ascii'))

            finally:
                connection_socket.close()

Сообщение об ошибке при использовании комментируемого оператора with:

Traceback (most recent call last):
  File "./test.py", line 26, in <module>
    with server_socket.accept() as (connection_socket, _):
AttributeError: __exit__

Предположительно, это связано с тем, что у кортежа нет атрибута __exit__, необходимого для with.


person dshepherd    schedule 11.10.2014    source источник


Ответы (1)


Возвращаемое значение socket.socket имеет встроенный менеджер контекста, реализующий __exit__ и __enter__. Кортеж, возвращаемый accept, не работает, но вы можете выделить клиентский сокет и адрес из кортежа и использовать with только для клиентского сокета:

import socket

with socket.socket() as s:
    s.bind(('',8000))
    s.listen(1)
    c,a = s.accept(s)
    with c:
        while True:
            data = c.recv(1024)
            if not data: break
            c.sendall(data)
person Mark Tolonen    schedule 11.10.2014