🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

3167閲覧

クラス外部からコンストラクタの呼び出しを禁止したい

Watching

総合スコア56

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2020/12/17 10:33

コンストラクタは async,await を利用した非同期関数にできないので、それらを利用しようと思った場合、オブジェクトを作成して一連の作成時処理を呼び出した後そのオブジェクトを返すメンバを作る必要があります。
そこで、外部からコンストラクタを呼び出されてしまうと、実行してほしい処理が実行されなくて困るので、外部からの呼び出しを禁止する方法はありますか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2020/12/17 10:50

所謂シングルトンでしょうか?それとも別物でしょうか?
guest

回答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
teamikl

総合スコア8729

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Watching

2020/12/18 03:36 編集

__await__を利用することでオブジェクトをコルーチンにできることはわかりました。しかし、それを学習できる適切なサイトが見つかりません。リファレンスも見てきましたが、説明が少なさ過ぎて難解です。もしご存じでしたら教えていただけませんか?
teamikl

2020/12/18 05:21

恐らく既に調べられたと思われる、難解なものしか知りません。 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 等 前提知識として、(双方向)ジェネレーターの実装詳細の理解は必須になると思います。
Watching

2020/12/18 10:13

__await__は今の自分の手には負えなさそうです。そのうち理解が深まってからまた挑戦してみようと思います。 ちなみにですが、提示してくれたソースコードに手を加えて実行すると、すぐにオブジェクトが破棄されてしまっています。__await__は戻り値としてイテレータの実装されたクラスを返さないといけないようです。
teamikl

2020/12/19 01:49

> すぐにオブジェクトが破棄されてしまっています。 __await__とは関係ない、オブジェクトの生存期間の問題です。 → 対策: ワンライナーの箇所を、インスタンス変数等に保持するように。 > __await__は戻り値としてイテレータの実装されたクラスを返さないといけない ここは、実際にはより複雑な部分で、普通のイテレータを返すだけではエラーになります。 ドキュメントが少ない理由が、言語仕様では枠組のみの提供で それをどのように使うのは、コルーチンを実行する仕組み (asyncio や trio) 次第なので、 現状ではやはり、実際のソースを読むくらいしか情報がなさそうです。 追記: 情報の少なさから、アプリケーション向けというよりは、 ライブラリやフレームワーク製作者向けなのかもしれません。
Watching

2020/12/19 01:59 編集

変数等に保持するように変更してしても…ということです。 _sleep().__await__()が完了した時に破棄されていると思います。 おそらくイテレーションが終了したので自動的に破棄されたのではないでしょうか。
teamikl

2020/12/19 02:12

__await__ の戻り値が適切でない場合は、TypeError や RuntimeError の例外が投げられます。 オブジェクトの破棄に関しては、実際のコードのオブジェクトの生存期間の管理次第なので、 提示されてる情報だけでは、なんとも言えません。
guest

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

参考:https://stackoverflow.com/questions/25040834/prevent-other-classes-methods-from-calling-my-constructor

注)この方法によってもFoo.__new__(Foo)という呼び出し方はできてしまう。

投稿2020/12/17 10:57

編集2020/12/17 11:59
sfdust

総合スコア1137

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問