コンストラクタは async,await を利用した非同期関数にできないので、それらを利用しようと思った場合、オブジェクトを作成して一連の作成時処理を呼び出した後そのオブジェクトを返すメンバを作る必要があります。
そこで、外部からコンストラクタを呼び出されてしまうと、実行してほしい処理が実行されなくて困るので、外部からの呼び出しを禁止する方法はありますか?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
所謂シングルトンでしょうか?それとも別物でしょうか?
回答2件
0
コンストラクタは async,await を利用した非同期関数にできないので、
具体的なコードがないので、状況次第ですが
__await__ メソッドを実装するではだめですか?
オブジェクトをコルーチンとしてのように振る舞わせることは可能です。
python
1import asyncio 2 3class C: 4 def __init__(self): 5 print("init C") 6 self._coro = self._sleep() 7 8 def __del__(self): 9 print("del C") 10 11 def __await__(self): 12 return self._coro.__await__() 13 14 async def _sleep(self): 15 await asyncio.sleep(1) 16 17async def main(): 18 await C() # <--- コンストラクタに async,await は使えないが、 19 # __await__ を実装する事で、オブジェクト自身を awaitable に 20 print("DONE") 21 22 23if __name__ == "__main__": 24 asyncio.run(main())
投稿2020/12/18 00:57
編集2020/12/19 02:20総合スコア8824
__await__を利用することでオブジェクトをコルーチンにできることはわかりました。しかし、それを学習できる適切なサイトが見つかりません。リファレンスも見てきましたが、説明が少なさ過ぎて難解です。もしご存じでしたら教えていただけませんか?
恐らく既に調べられたと思われる、難解なものしか知りません。
PEP 492 -- Coroutines with async and await syntax
https://www.python.org/dev/peps/pep-0492/
- 標準ライブラリ asyncio 内での __await__ の使われ方を調べる (task, future, coroutine)
- CPython のソースを調べる (ceval.c, typeobject.c, ~ _asynciomodule.c)
辺り。後は、実際に使われてるライブラリの実装でしょうか aiohttp 等
前提知識として、(双方向)ジェネレーターの実装詳細の理解は必須になると思います。
__await__は今の自分の手には負えなさそうです。そのうち理解が深まってからまた挑戦してみようと思います。
ちなみにですが、提示してくれたソースコードに手を加えて実行すると、すぐにオブジェクトが破棄されてしまっています。__await__は戻り値としてイテレータの実装されたクラスを返さないといけないようです。
> すぐにオブジェクトが破棄されてしまっています。
__await__とは関係ない、オブジェクトの生存期間の問題です。
→ 対策: ワンライナーの箇所を、インスタンス変数等に保持するように。
> __await__は戻り値としてイテレータの実装されたクラスを返さないといけない
ここは、実際にはより複雑な部分で、普通のイテレータを返すだけではエラーになります。
ドキュメントが少ない理由が、言語仕様では枠組のみの提供で
それをどのように使うのは、コルーチンを実行する仕組み (asyncio や trio) 次第なので、
現状ではやはり、実際のソースを読むくらいしか情報がなさそうです。
追記: 情報の少なさから、アプリケーション向けというよりは、
ライブラリやフレームワーク製作者向けなのかもしれません。
変数等に保持するように変更してしても…ということです。
_sleep().__await__()が完了した時に破棄されていると思います。
おそらくイテレーションが終了したので自動的に破棄されたのではないでしょうか。
__await__ の戻り値が適切でない場合は、TypeError や RuntimeError の例外が投げられます。
オブジェクトの破棄に関しては、実際のコードのオブジェクトの生存期間の管理次第なので、
提示されてる情報だけでは、なんとも言えません。
0
ベストアンサー
python
1class Foo(object): 2 def __init__(self): 3 raise NotImplementedError() 4 5 ''' 6 クラス共通の初期化処理が不要ならば下記関数は不要? 7 ''' 8 def __new__(cls): 9 bare_instance = object.__new__(cls) 10 # クラス共通の初期化処理を以下に書く 11 return bare_instance 12 13 @classmethod 14 def create(cls, value1, value2): 15 # 「オブジェクトを作成して」 16 self = cls.__new__(cls) 17 # 「一連の作成時処理を呼び出した後」 18 self.value1 = value1 19 self.value2 = value2 20 # 「そのオブジェクトを返す」 21 return self 22 23 def get_value1(self): 24 return self.value1 25 26 def get_value2(self): 27 return self.value2 28 29''' 30実行例 31''' 32 33f0 = Foo.create(0, 100) 34f1 = Foo.create(-10, -100) 35 36print(f0.get_value1()) 37print(f0.get_value2()) 38 39print(f1.get_value1()) 40print(f1.get_value2()) 41 42>> 0 43>> 100 44>> -10 45>> -100
g = Foo() >> NotImplementedError
注)この方法によってもFoo.__new__(Foo)という呼び出し方はできてしまう。
投稿2020/12/17 10:57
編集2020/12/17 11:59総合スコア1137
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。