Pythonのクラス/関数のモジュール化
こんにちは(@t_kun_kamakiri)
Pythonで書いた自分のコードをモジュール化することを考えます。
自分で書いたコードは機能ごとに関数やクラスにまとめておくとコードを再利用するときには利便性が増します。
ということで、あまり今までPythonのコードのモジュール化をしたことがなかったので練習がてらコードを書いてみました。
こちらの参考書を見ながらコードを実行していきます。
本記事のコードはgithubから入手できます。
モジュールの定義
まずは普通に関数を書いてmain()関数を実行します。
test001/main.pyの中身を以下とします。
import math
def get_trialgle(base, height):
"""
三角形の面積を計算
base: 底辺[m]
height: 高さ[m]
"""
return base * height /2
def get_circle(radius):
"""
円の面積を計算
Area : 円の面積[m]
radius: 半径[m]
"""
Area = radius * radius *math.pi
return Area
if __name__ == '__main__':
print(f'__name__ は{__name__}となっている。')
print(f'三角形の面積は{get_trialgle(10, 2)}')
print(f'円の面積は{get_circle(10)}')
コードを実行します。
PS C:\work\Python\20210226_Python_module\test001> python .\main.py
__name__ は__main__となっている。
三角形の面積は10.0
円の面積は314.1592653589793
if __name__ == '__main__':
の「__name__ 」はPythonの特殊な変数でモジュールが実行された際には「__main__」となっています。つまり実行されたメインのファイルなら「if __name__ == '__main__':」 のif文を満たすので、if文の中の処理が実行されるということです。
モジュールのインポート
では、main.pyに書いた関数を別のファイルに保存しておき、それをモジュールとして呼び出すようにします。
ファイル構成はこのようにしておきます。
get_math.py
import math
def get_trialgle(base, height):
"""
三角形の面積を計算
base: 底辺[m]
height: 高さ[m]
"""
return base * height /2
def get_circle(radius):
"""
円の面積を計算
Area : 円の面積[m]
radius: 半径[m]
"""
Area = radius * radius *math.pi
return Area
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
これをmian.pyで読み込むようにするは「from モジュール名 import 関数orクラス」と書きます。
main.py
from get_math import get_trialgle, get_circle
if __name__ == '__main__':
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
print(f'三角形の面積は{get_trialgle(10, 2)}')
print(f'円の面積は{get_circle(10)}')
【結果】
PS C:\work\Python\20210226_Python_module\test002> python .\main.py
----------get_math----------
__name__ はget_mathとなっている。
----------__main__----------
__name__ は__main__となっている。
三角形の面積は10.0
get_math.pyの中にも「print(f'__name__ は{__name__}となっている。')」と記述しておきました。
結果を見ての通り「__name__ はget_mathとなっている。」という結果になっており、importされたファイルでは__name__はそのファイル名になっていることがわかります。
※ちなみにmain.pyは呼び出すモジュールの中の関数を複数指定する場合は「from get_math import *」のように書けます。
main.py
from get_math import *
if __name__ == '__main__':
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
print(f'三角形の面積は{get_trialgle(10, 2)}')
print(f'円の面積は{get_circle(10)}')
ただ、モジュールが複数ある場合にはどのモジュールに「get_trialgle」が含まれていたのかがわからなくなるのであまりよくない記述かと思います。
また、main.pyを以下のように「import get_math」としてモジュール名だけ書いてもよいです。
import get_math
if __name__ == '__main__':
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
print(f'三角形の面積は{get_math.get_trialgle(10, 2)}')
print(f'円の面積は{get_math.get_circle(10)}')
「get_math.関数」のようにドットでつなげていきます。
また、毎回「「get_math.」と書くのが面倒な場合は呼び出し名を変更することもできます。
import get_math as g
if __name__ == '__main__':
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
print(f'三角形の面積は{g.get_trialgle(10, 2)}')
print(f'円の面積は{g.get_circle(10)}')
このようにすれば「g.get_trialgle(10, 2)」とget_mathの代わりにgと書くだけでよいということになります。
別のファイルにモジュールをまとめる
ファイル構成を以下のようにしておきます。
myget_math/get_math.py
import math
def get_trialgle(base, height):
"""
三角形の面積を計算
base: 底辺[m]
height: 高さ[m]
"""
return base * height /2
def get_circle(radius):
"""
円の面積を計算
Area : 円の面積[m]
radius: 半径[m]
"""
Area = radius * radius *math.pi
return Area
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
main.py
from myget_math import get_math
if __name__ == '__main__':
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
print(f'三角形の面積は{get_math.get_trialgle(10, 2)}')
print(f'円の面積は{get_math.get_circle(10)}')
これで「myget_math」のパッケージ↓の「get_math.py」モジュールにを利用することができます。
原理を考えるであればmain.pyを以下のようにしてもよいと考えられます。
main.py
import myget_math.get_math
if __name__ == '__main__':
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
print(f'三角形の面積は{myget_math.get_math.get_trialgle(10, 2)}')
print(f'円の面積は{myget_math.get_math.get_circle(10)}')
「myget_math.get_math」のように「パッケージ.モジュール」で読み込ませて使う際も「myget_math.get_math.get_trialgle(10, 2)」のように書けばいいわけです・・・が面倒ですよね。
長い「import myget_math.get_math」を「g」と置き換えればすっきりします。
main.py
import myget_math.get_math as g
if __name__ == '__main__':
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
print(f'三角形の面積は{g.get_trialgle(10, 2)}')
print(f'円の面積は{g.get_circle(10)}')
パッケージを初期化する
ただ「import myget_math.get_math as g」自体が長いので「myget_math」の中にパッケージを初期化する「__init__.py」を置いてその中に使用するモジュールを書いておきます。
「myget_math/__init__.py」
from myget_math import get_math
print('====実行された====')
このように書いておくことでmain.pyが実行された時点で「__init__.py」が読み込まれて上記のパッケージとモジュールを指定して使うことができます。
main.py
import myget_math
if __name__ == '__main__':
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
print(f'三角形の面積は{myget_math.get_math.get_trialgle(10, 2)}')
print(f'円の面積は{myget_math.get_math.get_circle(10)}')
このようにmain.pyの中にもパッケージを指定するだけで良いので記述がすっきりします。
「myget_math/get_math.py」は特に変更はなし。
import math
def get_trialgle(base, height):
"""
三角形の面積を計算
base: 底辺[m]
height: 高さ[m]
"""
return base * height /2
def get_circle(radius):
"""
円の面積を計算
Area : 円の面積[m]
radius: 半径[m]
"""
Area = radius * radius *math.pi
return Area
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
【結果】
PS C:\work\Python\20210226_Python_module\test009> python .\main.py
----------myget_math.get_math----------
__name__ はmyget_math.get_mathとなっている。
====実行された====
----------__main__----------
__name__ は__main__となっている。
三角形の面積は10.0
円の面積は314.1592653589793
main.pyを実行すると「import myget_math」➡「__init__.pyの中のfrom myget_math import get_math」が読み込まれ➡「print('====実行された====')」が実行されたという流れで実行されています。
「import myget_math」を実行しただけで「myget_math」のパッケージ内の「__init__.py」を読みに行っているというのがわかります。
次のようにモジュールが複数になってくると以下のように「__init__.py」に読み込むモジュールを記述しておきます。
「myget_math/__init__.py」
from myget_math import get_math
from myget_math import get_math_multi
print('====実行された====')
「myget_math/get_math.py」
import math
def get_trialgle(base, height):
"""
三角形の面積を計算
base: 底辺[m]
height: 高さ[m]
"""
return base * height /2
def get_circle(radius):
"""
円の面積を計算
Area : 円の面積[m]
radius: 半径[m]
"""
Area = radius * radius *math.pi
return Area
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
「myget_math/get_math_multi.py」←追加
import math
def get_trialgle2times(base, height):
"""
四角形の面積は三角形の面積の2倍
base: 底辺[m]
height: 高さ[m]
"""
triangle = base * height /2
return 2 *triangle
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
【結果】
PS C:\work\Python\20210226_Python_module\test010> python .\main.py
----------myget_math.get_math----------
__name__ はmyget_math.get_mathとなっている。
----------myget_math.get_math_multi----------
__name__ はmyget_math.get_math_multiとなっている。
====実行された====
----------__main__----------
__name__ は__main__となっている。
三角形の面積は10.0
円の面積は314.1592653589793
四角形の面積は20.0
結果はこのようになりました。
「__init__.py」の中身は以下のようにパッケージを相対位置として読み込ませてもよいです。
「myget_math/__init__.py」
from . import get_math
from . import get_math_multi
print('====実行された====')
クラスにまとめておく
ファイルを複数にわけるのも面倒なので計算をさせる機能をひつのファイルにまとめて計算する機能を関数としてクラスの中に入れておきます。
「myget_math/__init__.py」
from .get_math_multi import CalcMath
print('====実行された====')
「myget_math/get_math_multi.py」←この中にクラスを作ります。
import math
class CalcMath:
def __init__(self, base, height, radius):
self.base = base
self.height = height
self.radius = radius
def get_trialgle(self):
"""
三角形の面積を計算
base: 底辺[m]
height: 高さ[m]
"""
return self.base * self.height /2
def get_trialgle2times(self):
"""
四角形の面積は三角形の面積の2倍
base: 底辺[m]
height: 高さ[m]
"""
triangle = self.base * self.height /2
return 2 *triangle
def get_circle(self):
"""
円の面積を計算
Area : 円の面積[m]
radius: 半径[m]
"""
Area = self.radius * self.radius *math.pi
return Area
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
これをmain.pyからクラスを読み込むようにして、各関数を呼び出せばよいですね。
main.py
import myget_math
if __name__ == '__main__':
calc = myget_math.get_math_multi.CalcMath(10, 100, 1000)
print('-'*10 + f'{__name__}' + '-'*10)
print(f'__name__ は{__name__}となっている。')
print(f'三角形の面積は{calc.get_trialgle()}')
print(f'四角形の面積は{calc.get_trialgle2times()}')
print(f'円の面積は{calc.get_circle()}')
このようにするとmainファイルはすっきり書くことができます。
【結果】
PS C:\work\Python\20210226_Python_module\test012> python .\main.py
----------myget_math.get_math_multi----------
__name__ はmyget_math.get_math_multiとなっている。
====実行された====
----------__main__----------
__name__ は__main__となっている。
三角形の面積は500.0
四角形の面積は1000.0
円の面積は3141592.653589793
あまりクラスの使い方は慣れていないですが、プログラムの機能が多くなりすぎた場合は機能ごとに一度整理をしたほうが再利用する際には便利になりますね。
追記:記事にまとめました
noteの内容をブログ記事にまとめました。
【Python初心者】別ファイルの関数やクラスの実行(モジュール化)
Twitter➡@t_kun_kamakiri
Instagram➡kamakiri1225
ブログ➡宇宙に入ったカマキリ(物理ブログ)
ココナラ➡物理の質問サポートサービス
コミュニティ➡製造業ブロガー
この記事が気に入ったらサポートをしてみませんか?