__init__에서 await로 클래스 속성을 설정하는 방법
await
생성자 또는 클래스 본문에서 클래스를 어떻게 정의 할 수 있습니까?
예를 들어 내가 원하는 것 :
import asyncio
# some code
class Foo(object):
async def __init__(self, settings):
self.settings = settings
self.pool = await create_pool(dsn)
foo = Foo(settings)
# it raises:
# TypeError: __init__() should return None, not 'coroutine'
또는 클래스 본문 속성이있는 예 :
class Foo(object):
self.pool = await create_pool(dsn) # Sure it raises syntax Error
def __init__(self, settings):
self.settings = settings
foo = Foo(settings)
내 솔루션 (하지만 더 우아한 방법을보고 싶습니다)
class Foo(object):
def __init__(self, settings):
self.settings = settings
async def init(self):
self.pool = await create_pool(dsn)
foo = Foo(settings)
await foo.init()
대부분의 마법 방법이 함께 작동하도록 설계되지 않습니다 async def
/ await
일반적으로 만 사용되어야한다 - await
전용 비동기 마법 방법 내부 - __aiter__
, __anext__
, __aenter__
,와 __aexit__
. 다른 매직 메서드 내에서 사용하면 전혀 작동하지 않거나 (에서와 같이 __init__
) 비동기 컨텍스트에서 매직 메서드 호출을 트리거하는 모든 항목을 항상 사용하도록 강제합니다.
기존 asyncio
라이브러리는이 문제를 다음 두 가지 방법 중 하나로 처리하는 경향이 있습니다. 첫째, 사용 된 팩토리 패턴 ( asyncio-redis
예 :)을 확인했습니다.
import asyncio
dsn = "..."
class Foo(object):
@classmethod
async def create(cls, settings):
self = Foo()
self.settings = settings
self.pool = await create_pool(dsn)
return self
async def main(settings):
settings = "..."
foo = await Foo.create(settings)
다른 라이브러리는 팩토리 메소드가 아닌 객체를 생성하는 최상위 코 루틴 함수를 사용합니다.
import asyncio
dsn = "..."
async def create_foo(settings):
foo = Foo(settings)
await foo._init()
return foo
class Foo(object):
def __init__(self, settings):
self.settings = settings
async def _init(self):
self.pool = await create_pool(dsn)
async def main():
settings = "..."
foo = await create_foo(settings)
create_pool
에서 기능 aiopg
당신이 호출 할 것을는 __init__
사실이 정확한 패턴을 사용하고 있습니다.
이것은 적어도 __init__
문제를 해결합니다. 내가 기억할 수있는 비동기 호출을 수행하는 클래스 변수를 본 적이 없기 때문에 잘 정립 된 패턴이 나타 났는지 모르겠습니다.
funsies를위한 또 다른 방법 :
class aobject(object):
"""Inheriting this class allows you to define an async __init__.
So you can create objects by doing something like `await MyClass(params)`
"""
async def __new__(cls, *a, **kw):
instance = super().__new__(cls)
await instance.__init__(*a, **kw)
return instance
async def __init__(self):
pass
#With non async super classes
class A:
def __init__(self):
self.a = 1
class B(A):
def __init__(self):
self.b = 2
super().__init__()
class C(B, aobject):
async def __init__(self):
super().__init__()
self.c=3
#With async super classes
class D(aobject):
async def __init__(self, a):
self.a = a
class E(D):
async def __init__(self):
self.b = 2
await super().__init__(1)
# Overriding __new__
class F(aobject):
async def __new__(cls):
print(cls)
return await super().__new__(cls)
async def __init__(self):
await asyncio.sleep(1)
self.f = 6
loop = asyncio.get_event_loop()
e = loop.run_until_complete(E())
e.b # 2
e.a # 1
c = loop.run_until_complete(C())
c.a # 1
c.b # 2
c.c # 3
f = loop.run_until_complete(F()) # Prints F class
f.f # 6
별도의 공장 방법을 권장합니다. 안전하고 간단합니다. 그러나 async
버전 을 고집하는 경우 다음과 __init__()
같은 예가 있습니다.
def asyncinit(cls):
__new__ = cls.__new__
async def init(obj, *arg, **kwarg):
await obj.__init__(*arg, **kwarg)
return obj
def new(cls, *arg, **kwarg):
obj = __new__(cls, *arg, **kwarg)
coro = init(obj, *arg, **kwarg)
#coro.__init__ = lambda *_1, **_2: None
return coro
cls.__new__ = new
return cls
용법:
@asyncinit
class Foo(object):
def __new__(cls):
'''Do nothing. Just for test purpose.'''
print(cls)
return super().__new__(cls)
async def __init__(self):
self.initialized = True
async def f():
print((await Foo()).initialized)
loop = asyncio.get_event_loop()
loop.run_until_complete(f())
산출:
<class '__main__.Foo'>
True
설명:
클래스 생성은 coroutine
자체 인스턴스 대신 객체를 반환해야합니다 .
If you're using Python3.7 or newer then you can use asyncio.run:
import asyncio
# some code
class Foo(object):
async def __init(self):
self.pool = await create_pool(dsn)
def __init__(self, settings):
self.settings = settings
asyncio.run(self.__init)
foo = Foo(settings)
Note, this won't work if you're instantiating Foo
in an asynchronous function that's already running. See this blog post for a discussion on how to handle this scenario and a nice discussion of asynchronous programming in Python.
참고URL : https://stackoverflow.com/questions/33128325/how-to-set-class-attribute-with-await-in-init
'IT박스' 카테고리의 다른 글
ASP.NET Core를 사용하여 절대 URL 가져 오기 (0) | 2020.12.04 |
---|---|
TypeScript에서 중첩 클래스를 만들 수 있습니까? (0) | 2020.12.04 |
Woocommerce에서 맞춤 제품 속성 가져 오기 (0) | 2020.12.03 |
터미널에서 현재 분기 및 폴더 경로를 표시하려면 어떻게해야합니까? (0) | 2020.12.03 |
오래된 데이터에 대한 UICollectionView 어설 션 오류 (0) | 2020.12.03 |