'Asynchronous property setter
Let us suppose we have a class with a property that can only be set asynchronously. Is there a way to make this work without explicitly calling a setter?
MNWE:
import asyncio
loop = asyncio.get_event_loop()
class AsyncTest:
def __init__(self, attrib):
self._attrib = attrib
@property
def attrib(self):
return self._attrib
@attrib.setter
async def set_attrib(self, attrib):
await asyncio.sleep(1.0)
self._attrib = attrib
async def main():
t = AsyncTest(1)
print(t.attrib)
await t.attrib = 3
print(t.attrib)
asyncio.ensure_future(main())
loop.run_forever()
This fails with
File "asyncprop.py", line 22
await t.attrib = 3
^
SyntaxError: can't assign to await expression
which is not surprising, given that the grammar for await
is
await ::= ["await"] primary
So it seems we are bound to forget this nice @property
and resign ourselves to using getters and setters for asynchronous operations. Did I miss something?
Solution 1:[1]
You can't nest a statement inside another statement; assignment is a statement, and so is await
. You could use setattr()
to set attributes in an expression:
await setattr(t, 'attrib', 3)
However, a property
wraps the setter in a way that does not support async
methods (they are not awaitable), so you are still better off with an explicit setter method.
Solution 2:[2]
You can use the async-property
package: https://pypi.org/project/async-property/
Example:
from async_property import async_property
class Foo:
@async_property
async def remote_value(self):
return await get_remote_value()
f = Foo()
await f.remote_value
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Ryan Anguiano |