実現したいこと
pythonでオブジェクトごとに、同じクラスから作ったインスタンスの数を数えたいです。
できれば呼び出されたクラス側でカウントをしていきたいです。
よろしくお願いいたします。
該当のソースコード
python
1class Base(): 2 def __init__(self): 3 self.obj = Product() 4 self.obj = Product() 5 6class Product(): 7 num = 0 8 def __init__(self): 9 Product.num += 1 10 print(Product.num) 11 12if __name__ == '__main__': 13 test1 = Base() 14 test2 = Base() 15 16# これをインスタンスごとに独立にnumを増やしたい 17# Productを改変して、結果が1234 ではなく1212となるようにしたい
試したこと
クラス変数ではなく、インスタンス変数にすると常に1になってしまう。
inspect()では呼び出し元のインスタンス名の取得の仕方がわからなかった。
補足情報(FW/ツールのバージョンなど)
python3
以下のような質問にはグッドを送りましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
下記のような質問は推奨されていません。
- 間違っている
- 質問になっていない投稿
- スパムや攻撃的な表現を用いた投稿
適切な質問に修正を依頼しましょう。
回答2件
1
python
1import inspect 2 3class Base(): 4 def __init__(self): 5 self.obj = Product() 6 self.obj = Product() 7 8class Product(): 9 def __init__(self): 10 base = inspect.stack()[1].frame.f_locals['self'] 11 base.num = getattr(base, 'num', 0) 12 base.num += 1 13 print(base.num) 14 15if __name__ == '__main__': 16 test1 = Base() 17 test2 = Base() 18 19# 1 20# 2 21# 1 22# 2
投稿2022/12/04 06:35
総合スコア16234
0
ベストアンサー
GCによるオブジェクトの破棄は考えなくても大丈夫ですか?
呼び出されたクラス側でカウント
呼び出し元のインスタンスに依存するのは、
クラスの設計的に、Baseに依存するならカウントは Base 側で行わないと
Productクラスの再利用性が犠牲になります。
実質 Base クラス内でしかインスタンスを生成できなくなり、
functools.partial lambda での利用ができなくなったり、
単体テストを作成するのにひと手間必要になり、利便性が損なわれます。
python
1class Base: 2 def __init__(self): 3 self.count = 0 4 self.obj = Product(self) 5 self.obj = Product(self) 6 7class Product: 8 # NOTE: 明示的に baseオブジェクトを渡す 9 def __init__(self, base): 10 assert isinstance(base, Base) 11 base.count += 1 12 self.base = base 13 14 # ※ デストラクタを考慮するかどうかは、要件次第 15 def __del__(self): 16 self.base.count -= 1 17 18 19# 明示的に渡すことで、Base 外でも base を与えれば Product のインスタンスを作れるようになります。 20# => 単体テストや lambda での利用に配慮
Base 側でカウントする場合は、
Product のデストラクタをどう検知するかという問題がでてきますが、
weakref.WeakSet を使うことで、解消できます。
python
1 2from weakref import WeakSet 3 4class Base: 5 def __init__(self): 6 self._counter = WeakSet() # 生存しているオブジェクトのみを数える場合 7 self._total = 0 # 累計の生成数をカウントしたい場合 8 9 self.obj = self.createProduct() 10 self.obj = self.createProduct() # この時点で前に生成した self.obj は破棄される 11 12 def createProduct(self, *args, **kw): 13 obj = Product(*args, **kw) 14 self._counter.add(obj) 15 self._total += 1 16 return obj 17 18 @property 19 def total(self): 20 return self._total 21 22 @property 23 def count(self): 24 return len(self._counter) 25 26class Product: 27 def __init__(self, num=0): 28 self.num = num 29 30 def __repr__(self): 31 return f"<{self.__class__.__name__} {self.num=}>" 32 33 34if __name__ == "__main__": 35 36 base = Base() 37 print(base) # 1 38 obj = base.createProduct() 39 print(base.count) # 2 40 del obj 41 print(base.count) # 1 42 43 from functools import partial 44 create10 = partial(base.createProduct, 10) 45 obj = create10() 46 print(obj) 47 print(base.count) # 2 48 49 create12 = lambda: base.createProduct(12) 50 obj2 = create12() 51 print(base.count) # 3 52
投稿2022/12/04 09:11
編集2022/12/05 03:17総合スコア8534
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
回答へのコメント
関連した質問
解決済
回答2
クリップ1
更新
2023/01/24
Pythonのオーバーライド時にグローバル変数だけ変更したい
解決済
回答2
クリップ0
更新
2022/12/06
pythonでオブジェクトごとに作ったインスタンスの数を数えたい
解決済
回答2
クリップ0
更新
2023/01/27
pythonでの画像編集(ガンマ変換)
解決済
回答1
クリップ0
更新
2022/12/17
Python オーバーライドのシステム設計
解決済
回答3
クリップ0
更新
2023/01/29
classの中の、整数と文字を一緒にアウトプットするメソッドの記述について
解決済
回答1
クリップ0
更新
2023/01/21
コードを書く上で、__init__を使った場合と、使わない場合の使い分けなどありますか?
受付中
回答1
クリップ2
更新
2023/01/29
jsとgasによるdoPostとfetch間によるhtmlファイルの受け渡しについて
受付中
回答1
クリップ0
更新
2023/01/19
Whisperで文字起こしをしたいが、soundcardでの音声の処理時にエラーが出る
同じタグがついた質問を見る
オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。
Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
2022/12/04 23:59
2022/12/05 01:00
2022/12/05 16:46