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__
?
答案 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
!