__init__ 中依赖协程的变量应该如何定义?
How should I define a variable that depends on a coroutine in __init__?
在classWizard
中,我想将属性wand
设置为协程返回的值magic
。
class Wizard:
async def acquire_wand(self):
self.wand = await magic()
此代码被视为 "bad 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()
我可以在 __init__
中将 wand
设置为 None
并在任何访问它的地方使用 if self.wand is None:
,但这看起来很混乱和笨拙。
如何确保 wand
在整个 class 中定义?
将需要 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()
尚未测试代码,如果有效请告诉我们!
似乎使用以下方法是解决此问题的最佳方法。
class Wizard:
def __init__(self):
self.wand = None
async def learn(self):
self.wand = await magic()
async def perform_spell(self):
if self.wand is None:
raise Exception("You must first learn to use a wand!")
self.wand.wave()
技术上有一个重写 __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 通常不是一个好主意,请考虑一下。
我想你得到了你的建议,但我想质疑你的前提。谁告诉你是"considered bad Python"?每当我需要它们记住某些东西时,我总是给我的对象赋予属性。他们有 __dict__
是有原因的。 Python 不是 Java。
在classWizard
中,我想将属性wand
设置为协程返回的值magic
。
class Wizard:
async def acquire_wand(self):
self.wand = await magic()
此代码被视为 "bad 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()
我可以在 __init__
中将 wand
设置为 None
并在任何访问它的地方使用 if self.wand is None:
,但这看起来很混乱和笨拙。
如何确保 wand
在整个 class 中定义?
将需要 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()
尚未测试代码,如果有效请告诉我们!
似乎使用以下方法是解决此问题的最佳方法。
class Wizard:
def __init__(self):
self.wand = None
async def learn(self):
self.wand = await magic()
async def perform_spell(self):
if self.wand is None:
raise Exception("You must first learn to use a wand!")
self.wand.wave()
技术上有一个重写 __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 通常不是一个好主意,请考虑一下。
我想你得到了你的建议,但我想质疑你的前提。谁告诉你是"considered bad Python"?每当我需要它们记住某些东西时,我总是给我的对象赋予属性。他们有 __dict__
是有原因的。 Python 不是 Java。