在课程Wizard
中,我想将属性wand
设置为协程magic
返回的值。
class Wizard:
async def acquire_wand(self):
self.wand = await magic()
但是,此代码被视为“糟糕的Python”,因为wand
中未定义__init__
。但是,我无法在__init__
中对其进行定义,因为await
只能在async
hronous函数中使用。
class Wizard:
def __init__(self):
self.wand = None
async def acquire_wand(self):
self.wand = await magic()
async def perform_spell(self):
if self.wand is None:
await self.acquire_wand()
self.wand.wave()
我可以在wand
中将None
设置为__init__
,并在访问它的任何地方使用if self.wand is None:
,但这看起来很麻烦且不实用。
如何确保在整个课程中定义wand
?
答案 0 :(得分:5)
从技术上讲,有一个覆盖__new__
方法的技巧:
class InitCoroMixin:
""" Mixin for create initialization coroutine
"""
def __new__(cls, *args, **kwargs):
""" This is magic!
"""
instance = super().__new__(cls)
@asyncio.coroutine
def coro():
instance.__init__(*args, **kwargs)
yield from instance.__ainit__()
return instance
return coro()
@asyncio.coroutine
def __ainit__(self):
raise NotImplementedError
请参阅aiohttp_traversal代码以获取完整示例。
但我强烈反对这种方法:在构造函数中使用I / O通常是一个坏主意,请考虑一下。
答案 1 :(得分:1)
在装饰器中包含需要self.wand
的函数,这将产生一个干净且可行的解决方案:
def with_wand(fn):
def wrapper(self):
if not self.wand:
await self.acquire_wand()
fn(self)
return wrapper
@with_wand
async def perform_spell(self):
self.wand.wave()
尚未测试代码,请告知我们是否有效!
答案 2 :(得分:0)
似乎使用以下内容是解决此问题的最佳方法。
?substitute
答案 3 :(得分:0)
我认为你得到了你的建议,但我想质疑你的前提。谁告诉你它被认为是糟糕的Python"?每当我需要它们记住某些东西时,我总是给出我的对象属性。他们有__dict__
个原因。 Python不是Java。