asyncio create_connection协议工厂

时间:2017-01-18 18:59:47

标签: python python-3.x lambda python-asyncio

Python 3的asyncio模块中的create_connection函数将其作为协议工厂的第一个参数。该文档包含以下注释:

  

注意protocol_factory可以是任何类型的可调用,不一定是类。例如,如果要使用预先创建的协议实例,则可以传递lambda:my_protocol。

因此,您可以使用lambda传递实例,如下所示:

create_connection(lambda: Protocol(a, b, c))

另一种方法是将__call__定义为return self,这样您就可以在不定义lambda的情况下传递实例。

protocol = Protocol(a, b, c)
create_connection(protocol)

有没有理由使用lambda,因为文档建议在类上定义__call__

2 个答案:

答案 0 :(得分:0)

简答:

lambda应该优先使用,因为它更具可读性 - 无需仔细检查Protocol类代码就可以轻松理解它。

<强>解释

BaseEventLoop.create_connection来自BaseEventLoop._create_connection_transport ref,它从Protocol类实例化协议对象,如下所示:

    protocol = protocol_factory()

我们可以在没有事件循环代码的情况下以简化的方式呈现问题,以演示如何实例化协议:

class Prococol:
   pass

def create_connection(Protocol):
   protocol = Protocol()

create_connection(Protocol)

所以,&#34;协议=协议()&#34;需要使用参数。这可以通过使用lambda:

class Protocol:
  def __init__(self, a):
     self.a = a

def create_connection(Protocol):
  protocol = Protocol()

create_connection(lambda: Protocol(1))

或OP建议的替代建议是使对象成为可调用对象:

class Protocol:
  def __init__(self, a):
     self.a = a

  def __call__(self):
     return self

def create_connection(Protocol):
  protocol = Protocol()

create_connection(Protocol(1))

功能上两者都有效,因此这是一个更好的实践问题。我认为lambda方法更好,因为查看最后一行create_connection(lambda: Protocol(1))清楚地表明我们正在传递给create_connection函数,该函数在调用时返回一个对象,而传递一个可调用对象会使代码不易读取 - 因为需要仔细检查Protocol类以确定实例化对象也是可调用实体。

Udi对这个问题的回答说,使用def __call__(self): return self,不能使用create_server(这不是问题所在的那个),因为它将重用实例化对象的一个​​实例。这种观察是正确的,但从该答案中省略的是可以轻松调整可调用以使用create_server。例如:

class Protocol:
  def __init__(self, a):
     self.a = a

  def __call__(self):
     return Protocol(self.a)

底线使用__call__应该像lambda方法一样工作。出于可读性原因,应优先使用lambda的原因。

答案 1 :(得分:0)

注意这两行之间的区别:

List

以下是来自asyncio docs的echo客户端示例,经过修改后可与选项#1一起使用:

loop.create_connection(MyProtocol, '127.0.0.1', 8888)    # Option #1
loop.create_connection(MyProtocol(), '127.0.0.1', 8888)  # Option #2

如果您选择使用选项#2,则需要实施适用于class MyEchoClientProtocol(asyncio.Protocol): def connection_made(self, transport): message = "hello" transport.write(message.encode()) print('Data sent: {!r}'.format(message)) def data_received(self, data): print('Data received: {!r}'.format(data.decode())) def connection_lost(self, exc): print('The server closed the connection') print('Stop the event loop') loop.stop() loop = asyncio.get_event_loop() coro = loop.create_connection(MyEchoClientProtocol, '127.0.0.1', 8765) loop.run_until_complete(coro) loop.run_forever() loop.close() 实例MyProtocol.__call__(self)

虽然这可能适用于MyProtocol,但由于您的create_connection只会被调用一次,因此对create_server__call__参数效果不佳:

protocol_factory

这里多次调用... # Each client connection will create a new protocol instance coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8888) ... 来创建新的protocol_factory实例。使用Protocol和定义EchoServerClientProtocol()只会重用def __call__(self): return self

的一个实例