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

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

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

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python 3.x

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

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

パラメータ

関数やプログラム実行時に与える設定値をパラメータと呼びます。

Q&A

解決済

3回答

1190閲覧

自作のツールで、パラメータや機能の管理をうまく行いたい(保守性を上げたい)

H.K2

総合スコア88

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python 3.x

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

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

パラメータ

関数やプログラム実行時に与える設定値をパラメータと呼びます。

0グッド

1クリップ

投稿2021/06/06 05:44

編集2021/06/06 05:47

前提・実現したいこと

周りの知り合いの間でPC操作を効率化するためのツールを作って、更新しています。
ツールは複数の機能(10程度)と、それぞれの機能に渡す、複数の仕向け(人別)の
パラメータがあります。(概略イメージは下記となります)

イメージ説明

これらについて、最近パラメータや機能の変更が多く、GUIと紐づく機能の管理がややこしく
なってきました。これらのパラメータの管理について保守性を上げたいのですが、
どのようなことに取り組めばよいでしょうか。
(今回の例では、簡単化のためにすべてベタで書きましたが、それぞれの処理を関数にはしてみましたが、あまり保守性が上がったように思えませんでした…)

該当のソースコード

Python

1 2# パラメータ読み込み処理(json, iniなどから…) 3conf_ini = configparser.ConfigParser() # パラメータ設定(例えばiniファイルの場合) 4...(中略) 5# パラメータ選択 6str_param_type = "DEFAULT" 7if param_type == "1": 8 str_param_type = "AAA" 9elif param_type == "2": 10 str_param_type = "BBB" 11elif param_type == "3": 12 str_param_type = "CCC" 13 ...(中略) 14# ツール種別選択 15tool_select_type = "YYY" 16if tool_type == "0": 17 tool_select_type = "XXX" 18elif tool_type == "1": 19 tool_select_type = "YYY" 20elif tool_type == "2": 21 tool_select_type = "ZZZ" 22 ...(中略) 23 24# その他もろもろの初期化処理など 25 26# 各種別のツールごとの処理 27if tool_type == "XXX": 28 execute_XXX(conf_ini, str_param_type) 29elif tool_type == "YYY": 30 execute_YYY(conf_ini, str_param_type) 31...(中略) 32

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

Python 3.7.6

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/06/06 06:35 編集

要件の具体化のため確認したいのですが、下記のような理解でいいでしょうか。 理解が間違っている部分があれば御指摘ください。   ・Aさん、Bさん、Cさんといったユーザーいずれも、使いたい機能(たとえば「担当製品の月次売上高の集計」「担当製品の地域別売上高集計」「顧客別進捗一覧の出力」みたいなもの)は共通している。その数が10個くらいある。   ・ツール使用者ごと(Aさん、Bさん、Cさん)に、使うデータや表示内容が異なる (例えば・Aさん、Bさん、Cさんごとに、担当製品が異なっている    ・ユーザー別売上集計において、Aさんは10百万円以上のユーザーを表示したいが、Bさんは2百万円以上のユーザーを表示したい、等の違いがある。 →そうした「異なるデータソースや表示方法等々」を、使用者(Aさん~Cさん)ごとに「str_param_type 」や「 tool_select_type」というパラメータで指定している) ・pythonスクリプトには、ツール使用者がデータを加工する上での共通機能となるものを関数として書いている。 関数呼び出し時に上記パラメータを指定することで、使用者ごとのニーズの違いを吸収している。   具体例として挙げたシチュエーションは異なるかもしれませんが、それは別として、今質問者さんが困っていることとして質問に書いた「最近パラメータや機能の変更が多く」「GUIと紐づく機能の管理がややこしくなってきた」「これらのパラメータの管理について保守性を上げたい」というところを噛み砕いていうと、 ・ツール使用者から「こういう機能が欲しい」というような追加要望が出たときに、それに対応しようとすると、共通機能として書いているpythonスクリプト上の処理関数の方も複数変更しなければならなくなり煩雑になっている。 ・逆に、共通機能として書いているpythonスクリプト上の「機能」(処理関数)を改善しようとすると、その変更の影響が、ツール使用者ごとのパラメータ設定にも影響し、変更箇所が多くなってしまう。 このような状況なので困っている、という理解でよろしいでしょうか?
H.K2

2021/06/06 11:56

ご質問ありがとうございます。ご質問の内容で正しいと考えています。 ツール配布するときはpyinstallerなどでexeにフリージングして配布となるのですが(ユーザはほとんどPythonスクリプトを実行する環境を持ってない)、機能追加、変更などがそれなりにあるため、exeにする手間なども考えると、コア部分をできるだけ触らず(既存の他の人の機能やパラメータに影響はなるべく与えたくない)、要望に対応できれば、と考えています。
guest

回答3

0

まずINIファイルはベースになるものと、カスタム用の2つを準備して、configparserでベースを読み込んで次にカスタムを読み込むようにすると管理が楽になると思います。

またINIファイルはセクションをうまく分けながら、各セクションと関数やクラスといった処理単位を対応させると以下の例のように結構スマートにかけます。

ご参考までに。

python

1 2from configparser import ConfigParser 3 4ini_base = ''' 5[print_nums] 6a = 1 7b = 2 8''' 9 10ini_custom = ''' 11[print_nums] 12b = 3 13c = 4 14''' 15 16def print_nums(**kwargs): 17 for key in kwargs: 18 print(key, '=', kwargs[key]) 19 20config = ConfigParser() 21config.read_string(ini_base) 22config.read_string(ini_custom) 23 24print_nums(**config['print_nums'])

投稿2021/06/06 06:41

YouheiSakurai

総合スコア6142

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

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

H.K2

2021/06/06 12:03

ご回答ありがとうございます。 なるほど、ベース側でみんな同じパラメータを読んで、custom側で、人別のファイルを用意して 読み取れば、それぞれのパラメータで上書きした状態で管理できる、ということでしょうか。 参考にさせていただきます。
guest

0

ベストアンサー

それぞれの機能のプラグイン化でしょうか。
サンプル提示が目的の為、エラー処理等は省略します。

python

1## 改善したいコード 2# 各種別のツールごとの処理 3if tool_type == "XXX": 4 execute_XXX(conf_ini, str_param_type) 5elif tool_type == "YYY": 6 execute_YYY(conf_ini, str_param_type)

python

1# STEP1: 辞書に纏めておく 2 3execute_dict = { 4 "XXX": execute_XXX, 5 "YYY": execute_YYY, 6} 7 8execute = execute_dict[tool_type] 9execute(conf_init, str_param_type)

python

1# STEP2: プラグイン化: 必要なモジュールのみ読み込む 2 3def load_execute_func(tool_type): 4 # 例: execute_XXX.py, execute_YYY.py ファイルに execute() 関数 5 modname = f"execute_{tool_type}" 6 module = __import__(modname) 7 return getattr(module, "execute") 8 9execute = load_execute_func(tool_type) 10execute(conf_init, str_param_type)

プラグインを扱うライブラリ等もありますが、
「設定ファイルから読み込んだ値に応じて、動的にモジュールをロードする」
という流れが共通する解決策です。


  • パラメータ選択
  • ツール種別選択

のコードは、数値 → 値の変換なので、辞書を使って key => value 変換できます。
もしくは、設定ファイルに記録する値を、直接プログラムで使う値にしてもいいかもしれません。
(値のチェックは必要です)

投稿2021/06/06 06:48

teamikl

総合スコア8664

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

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

teamikl

2021/06/06 07:36

具体的に保守性に影響する部分を言及しておくと 対応するケースが増える場合、 例えば execute_ZZZ が追加された時、 基盤となっている部分のコードは、変更しなくても済みます。 execute_ZZZ.py に execute 関数を実装して、テストは execute_ZZZ.execute のみで済みます。 → 既存のコードは変更しない為、既に検査済みの部分の再テストは発生しない。
H.K2

2021/06/06 12:09 編集

ご回答ありがとうございます! そうです。ご指摘のようなことがやりたいイメージでした。ちょっとコード実行して確かめてみます。 基盤部分は変更せず、機能部分だけ差し替えたりなどでうまく管理できれば、という感じで思っていました。プラグインを扱うライブラリ、というのもあるのでしょうか。Googleで検索してみたのですが、あまりそれっぽいものが見つからなかったのですが、便利なものなどありますでしょうか。(今くらいのユースケースだと、プラグインなど使わず、自前で実装したほうが良いでしょうか。)
teamikl

2021/06/06 13:12

具体的なところは、実際のユースケース次第なので、 第三者視点では判断しかねます。 プラグインの導入自体が保守性向上に直接繋がるわけではありませんが、 設計で適切にモジュールを切り分けられれば、変更のコストは抑えられます。 (プラグイン自体は、動的にモジュールを構成する為の手段という位置付けです) 保守性に影響する部分だと、 テストの自動化がどれくらい導入出来ているかの方が占める割合は大きそうです。 実装に関しては、 IDLE の extensions 等の実装を参考にしてみてはどうでしょう。 Python に付属の IDE で、idlelib 以下にサンプル idlelib/zzdummy があります。 https://docs.python.org/ja/3/library/idle.html ページ一番下IDLE 拡張 See the beginning of config-extensions.def in the idlelib directory for further information - https://github.com/python/cpython/blob/main/Lib/idlelib/config-extensions.def - https://github.com/python/cpython/blob/main/Lib/idlelib/extend.txt Tkinter だと次点で参考に出来そうなのは Thonny https://github.com/thonny/thonny/wiki/Plugins ---- プラグインシステムを提供するライブラリは、 py.test で使われてる pluggy や、openstack の stevedore 等。 (stevedore 導入は、パッケージ単位でプラグインを管理する事になるので 用途に対して「重たい」かも知れませんが、ドキュメントが詳しく書かれており 既存アプリケーションでのプラグインシステムの種類の調査等、 プラグインの仕組みを自分で構築する際も参考になりました) もし、Web 系のフレームワークを触ったことがあるなら、 WSGI のミドルウェアのコンセプト等もプラグインシステムを構築する上で参考になります。
H.K2

2021/06/06 13:26

ありがとうございます! おっしゃる通り、確かにユースケース次第ですね。ご回答いただいた内容で、確かにできそうなので、 まずは小さく始めてみて、必要に応じて+1していく形がよさそうですね。大変勉強になりました。
guest

0

おはようございます。

問題文読ませていただきました。

一度以下のようにまとめて、

python

1strParamTypeList = { 2 '1': 'AAA', 3 '2': 'BBB', 4 '3': 'CCC', 5} 6 7toolSelectTypeList = { 8 '0': 'XXX', 9 '1': 'YYY', 10 '2': 'ZZZ', 11} 12 13 14def execute_XXX(strParamType): 15 print('execute_xxx') 16 print(strParamType) 17 18 19def execute_YYY(strParamType): 20 print('execute_yyy') 21 print(strParamType) 22 23 24# パラメータ選択 25strParamType = 'DEFAULT' 26paramType = '2' 27strParamType = strParamTypeList[paramType] 28 29# ツール種別選択 30toolSelectType = "YYY" 31toolType = '0' 32toolSelectType = toolSelectTypeList[toolType] 33 34# 参考 : https://www.delftstack.com/ja/howto/python/python-call-function-from-a-string/ 35locals()['execute_' + toolSelectType](strParamType)

その後に、設定ファイルにまとめることを検討すると良さそうです。

ご確認のほど、よろしくお願いいたします。????‍♂️

投稿2021/06/06 23:17

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問