魔术方法中的协程?

时间:2020-01-30 10:34:46

标签: python python-3.x python-3.6 coroutine magic-methods

比方说,我在Python 3.6中拥有一个神奇的方法,例如:

def __str__(self):
    return 'a {self.color} car'.format(self=self)

现在我想在其中添加一个协程,例如:

async def __str__(self):
    await self.my_coro(args)
    return 'a {self.color} car'.format(self=self)

据我所知,有必要在def之前添加async,但这似乎不适用于魔术方法。有(简单的)解决方法还是完全不可能?

1 个答案:

答案 0 :(得分:2)

TLDR:没有解决方法,因为Python期望许多特殊方法使用特定类型。但是,某些特殊方法具有异步变体。


async def函数本质上是另一种函数。类似于生成器函数对生成器求值的方式,协程函数对等待器求值。

您可以将特殊方法定义为异步方法,但这会影响它们的返回类型。对于__str__,您得到的是Awatable[str]而不是裸露的str。由于Python在这里需要 一个str,因此会导致错误。

>>> class AStr:
...     async def __str__(self):
...         return 'Hello Word'
>>> str(AStr())

TypeError: __str__ returned non-string (type coroutine)

这会影响所有直接由Python解释的特殊方法:其中包括__str____repr____bool____len____iter__,{{1 }}和其他一些。通常,如果一种特殊方法与某些内部使用的功能(例如,用于直接显示的__enter__)或语句(例如,需要迭代器的str)有关,则不能为for


Python不会直接解释某些特殊方法。示例包括算术运算符(async__add__,...),比较(__sub____lt__,...)和查找(__eq__,{ {1}},...)。它们的返回类型可以是任何对象,包括等待对象。

您可以通过__get__定义此类特殊方法。这会影响它们的返回类型,但只需要客户端代码__getattribute__。例如,您可以定义async def用作await

+

await (a + b)机制中存在一些特殊方法,这些方法应返回一个等待的方法。这包括>>> def AWAIT(awaitable): ... """Basic event loop to allow synchronous ``await``""" ... coro = awaitable.__await__() ... try: ... while True: ... coro.send(None) ... except StopIteration as e: ... return e.args[0] if e.args else None ... >>> class APlus: ... def __init__(self, value): ... self.value = value ... async def __add__(self, other): ... return self.value + other ... >>> async def add(start, *values): ... total = start ... for avalue in map(APlus, values): ... total = await (avalue + total) ... return total ... >>> AWAIT(add(5, 10, 42, 23)) 80 await__aenter__。值得注意的是,__aexit__必须返回一个迭代器,而不是等待的迭代器。

您可以(在大多数情况下应该)将这些方法定义为__anext__。如果需要在相应的同步特殊方法中使用异步功能,请将相应的异步特殊方法__await__一起使用。例如,您可以定义一个异步上下文管理器。

async def
相关问题