質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

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

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

デザインパターン

デザインパターンは、ソフトウェアのデザインでよく起きる問題に対して、解決策をノウハウとして蓄積し再利用出来るようにした設計パターンを指します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

580閲覧

pythonで作ったインスタンスの数を、呼び出し元に依存せず数えたい

lukkio

総合スコア4

Python 3.x

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

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

デザインパターン

デザインパターンは、ソフトウェアのデザインでよく起きる問題に対して、解決策をノウハウとして蓄積し再利用出来るようにした設計パターンを指します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

0クリップ

投稿2022/12/09 06:01

前提

作ったインスタンスにクラス名+インスタンスの数を辞書のキーとして与えて、
test_1.print_name('FirstProduct1')
のようにクラス名+作成番号で作った辞書のキーでオブジェクトを呼び出せるようにするのが目的です。

呼び出し元(Main)にカウンターを持たせてしまうと、ファクトリーメソッドで作った回数(FirstProduct, SeconProduct)を数えてしまうために、それぞれのクラスを個別にカウントできません。

呼び出し側にそれぞれのファクトリー用のカウンターを持たせてしまうと、呼び出し側がファクトリーの知識を持ってしまうのでファクトリーを増やす際に呼び出し元(Main)の改変が必要になってしまいます。

該当のソースコードでは、呼び出される側にクラス変数を持たせていますが、新たに呼び出し元のインスタンス(Main)を作るとそれぞれのクラス(FirstProduct, SecondProduct)のカウンターがリセットされません。

そもそもクラス設計やデザインパターンの使い方が間違っているなどの指摘でもかまいません。わかりにくい質問かもしれませんが、よろしくお願いいたします。

実現したいこと

インスタンスの数を、呼び出し元に依存せず数えたい。
または、ファクトリーメソッドで作ったインスタンスにクラス名+作成数の名前をつけて辞書のキーにしたい。

該当のソースコード

python

1from abc import ABCMeta, abstractmethod 2import pprint 3 4class Main(): 5 def __init__(self): 6 self.obj = [] # productのオブジェクトリスト 7 self.obj_name = [] # productの名前リスト 8 self.obj_dict = {} # productの辞書 9 10 def create_obj(self, factory_type): 11 product = factory_type.create_product() # productのインスタンス作成 12 object_name = product.__class__.__name__ # productのクラス名 13 num_product = product.num # productの作成回数 14 15 self.obj.append(product) # オブジェクトリストの追加 16 self.obj_name.append(object_name + str(num_product)) # 名前(クラス名+作成番号)リストの追加 17 self.obj_dict = dict(zip(self.obj_name, self.obj)) # クラス名とオブジェクトのバインド 18 19 def print_name(self, product): 20 self.obj_dict[product].print_name() 21 22class Factory(metaclass=ABCMeta): # factory 23 @abstractmethod 24 def create_product(self): 25 pass 26 27class FirstFactory(Factory): # concrete factory 28 def create_product(self): 29 return FirstProduct() 30 31class SecondFactory(Factory): # concrete factory 32 def create_product(self): 33 return SecondProduct() 34 35class Product(metaclass=ABCMeta): #product 36 @abstractmethod 37 def print_name(self): 38 pass 39 40class FirstProduct(Product): # concrete product 41 num = 0 # インスタンス作成回数 42 def __init__(self): 43 FirstProduct.num += 1 44 45 def print_name(self): 46 print('First Product ' + str(FirstProduct.num)) 47 48class SecondProduct(Product): # concrete product 49 num = 0 # インスタンス作成回数 50 def __init__(self): 51 SecondProduct.num += 1 52 53 def print_name(self): 54 print('Second Product ' + str(FirstProduct.num)) 55 56if __name__ == '__main__': 57 test_1 = Main() # 一つ目のMainオブジェクト 58 test_1.create_obj(FirstFactory()) 59 test_1.create_obj(SecondFactory()) 60 61 test_2 = Main() # 二つ目のMainオブジェクト 62 test_2.create_obj(FirstFactory()) 63 test_2.create_obj(SecondFactory()) 64 65 pprint.pprint(test_1.obj_dict) 66 print() 67 pprint.pprint(test_2.obj_dict) 68 print() 69 70 test_1.print_name('FirstProduct1') 71 test_1.print_name('SecondProduct1') 72 test_2.print_name('FirstProduct2') 73 test_2.print_name('SecondProduct2') 74 75 76 # 辞書のキーをMainのインスタンス(test_1,test_2)ごとに1から始めたい 77 78 # 結果を 79 #First Product 1 80 #Second Product 1 81 #First Product 1 82 #Second Product 1 83 #にしたい

補足情報(FW/ツールのバージョンなど)

python 3.8.10

melian😄を押しています

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

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

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

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

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

can110

2022/12/09 06:50

現状、実現したい動作(結果)が分かりません。たとえば > # 辞書のキーをMainのインスタンス(test_1,test_2)ごとに1から始めたい のであればtest_2.print_name('FirstProduct2')において'FirstProduct2'というインスタンスは存在しないのではないでしょうか? あるいは、まずは無理やりでもいいので期待通りに機能するコードを作成、提示して そのうえでメンテナンス上など?の理由で「改変が必要」といった懸念点を解決する手段・手法について質問したほうがよいかと思います。
lukkio

2022/12/09 14:59

確かにそういう質問のほうがわかりやすいですし、解答しやすいですね。 今回はすでに解答をいただきましたが、次回からはそういう質問の仕方にしようと思います。 ご指摘ありがとうございました。
guest

回答1

0

ベストアンサー

Mainにカウンターを持たせると、Productクラスを増やすたびMainの改変が必要になると懸念されているようですが、そんなことはないと思います。
例えば、Mainに以下のような「キーがクラス名、値がカウンター」の辞書を持たせてはどうでしょう。

{'FirstProduct' : 3, 'SecondProduct' : 1}

クラス名は product.__class__.__name__ で取れますので、この形でカウンターを持てば、Productクラスが増えてもMainを改変する必要はありません。

実はPythonを書くのは初めてなのですが、ググりつつ辞書でカウンターを持つ形にコードを書き直してみました。

can110さんが言うように、上のコードにおいて'FirstProduct2'は存在しないので、実現したい意図と合っているのか少し疑問がありますが、そこはひとまず'FirstProduct1'にしています。

python

1from abc import ABCMeta, abstractmethod 2import pprint 3 4class Main(): 5 def __init__(self): 6 self.counter_dict = {} 7 self.obj_dict = {} 8 9 def create_obj(self, factory_type): 10 product = factory_type.create_product() # productのインスタンス作成 11 object_name = product.__class__.__name__ # productのクラス名 12 last_num = self.counter_dict.get(object_name, 0) 13 new_num = last_num + 1 14 product.num = new_num 15 self.counter_dict[object_name] = new_num 16 self.obj_dict[object_name + str(product.num)] = product 17 18 def print_name(self, product): 19 self.obj_dict[product].print_name() 20 21class Factory(metaclass=ABCMeta): # factory 22 @abstractmethod 23 def create_product(self): 24 pass 25 26class FirstFactory(Factory): # concrete factory 27 def create_product(self): 28 return FirstProduct() 29 30class SecondFactory(Factory): # concrete factory 31 def create_product(self): 32 return SecondProduct() 33 34class Product(metaclass=ABCMeta): #product 35 @abstractmethod 36 def print_name(self): 37 pass 38 39class FirstProduct(Product): # concrete product 40 def __init__(self): 41 pass 42 43 def print_name(self): 44 print('First Product ' + str(self.num)) 45 46class SecondProduct(Product): # concrete product 47 def __init__(self): 48 pass 49 50 def print_name(self): 51 print('Second Product ' + str(self.num)) 52 53if __name__ == '__main__': 54 test_1 = Main() # 一つ目のMainオブジェクト 55 test_1.create_obj(FirstFactory()) 56 test_1.create_obj(SecondFactory()) 57 58 test_2 = Main() # 二つ目のMainオブジェクト 59 test_2.create_obj(FirstFactory()) 60 test_2.create_obj(SecondFactory()) 61 62 pprint.pprint(test_1.obj_dict) 63 print() 64 pprint.pprint(test_2.obj_dict) 65 print() 66 67 test_1.print_name('FirstProduct1') 68 test_1.print_name('SecondProduct1') 69 test_2.print_name('FirstProduct1') 70 test_2.print_name('SecondProduct1')

投稿2022/12/09 07:22

編集2022/12/09 08:16
rim_yamamoto

総合スコア22

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

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

lukkio

2022/12/09 15:02 編集

解答していただいてありがとうございます。記述していただいた回答でやりたいことができました。 pythonを調べていただくとのと同時に、コードもより洗礼されたコードに書き直していただいてありがとうございます。 self.counter_dict = {} 「キーがクラス名、値がカウンター」の辞書を作ったうえで last_num = self.counter_dict.get(object_name, 0) キーごとのカウントを取得 new_num = last_num + 1 カウンターを増 product.num = new_num productのインスタンス変数にカウンター数を持たせ self.counter_dict[object_name] = new_num カウンターにProductごとのキーとカウンター数を追加 self.obj_dict[object_name + str(product.num)] = product Product名とカウンター数が付いたキーでオブジェクトを辞書に追加 ということですね。カウンター用の辞書をつくるという考えに至りませんでした。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問