実現したいこと
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
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
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
総合スコア19771
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総合スコア8664
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/12/05 00:50
2022/12/05 04:48 編集
2022/12/05 16:47
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/12/04 23:59
2022/12/05 01:00
2022/12/05 16:46