前回はPythonのモジュールやパッケージの実体が何であるかということについてお話しました。今回は簡単なモジュールを実際に作ってインポートしていこうと思います。
ファイルの準備
まずはモジュールのためのファイルを作成しましょう。VSCodeであればワークスペースのフォルダ名を右クリック→「新しいファイル」で、そのフォルダに新規ファイルを作成できます。
名前を付けましょう。今回は「my_module.py」としておきます。拡張子を忘れずに。
コードを記述する
ファイルが準備できたらコードを記述します。今回はクラスは定義せず、関数だけのコードです。
import random
def randmulti(x):
y = random.randint(0,10)
return x*y
def greeting(str = "ご主人"):
print("おはようございます。"+str+"さま♡")
if __name__ == '__main__':
print("これは自作モジュールです")
正しく動けば何でもかまいません。このコードでは1行目でrandomモジュールをインポートしています。このようにモジュール側に標準ライブラリや外部ライブラリをインポートしておくことも可能です。
if __name__ == ‘__main__’とは
おまじない?
最後の2行は「おまじない」としてなんとなく記述している方もいるかも知れません。僕も始めはおまじないとして書いていた記憶があります。
何しろこの__name__と’__main__’が初心者にとっては分かりにくいので、ここで押さえておきたいところです。
__name__の意味
まず__name__ですが、これは自動的に値が代入される特殊プロパティ(属性)です。インポートされた時、ここにはモジュール名(自身のファイル名)が自動的に入ります。
確認
実行用のファイルを同じディレクトリに用意して確かめてみましょう。
import my_module
print(my_module.__name__) #my_module
インポートされた場合、プロパティに代入されているのはファイル名です。つまりこのif文は、インポートされたときには実行されないということになります。ではどんな場合に実行されるか?
my_module.pyファイルを開いて、モジュールとしてではなく単独で走らせてみると、
#これは自作モジュールです
if文に記述した処理が実行されました。これはつまりモジュールとして作ったファイルを単独で実行した場合、そのファイルの特殊プロパティ__name__に’__main__’という文字列が代入されるということを意味しています。
実行ファイルの__name__は__’main’__
もう1つダメ押しで試してみましょう。真っ白な.pyファイルに下の1行だけ記述して普通に実行してみてください。
print(__name__) #__main__
Pythonの答えは「__main__」です。つまりどんな.pyファイルだろうが、実行ファイルの__name__プロパティは’__main__’になります。
モジュールとして記述した.pyファイルにこの文を書き入れるということは、「このファイルをもし普通に実行した場合、if文の処理を実行してくれ」というお願いをしているわけです。
モジュールとして実行する
話がそれてしまいましたが、ここまででエラーが出ていない方はモジュールをインポートして使うことができるはずです。試してみましょう。
import my_module
my_module.greeting("ぷーおん") #おはようございます。ぷーおんさま♡
print(my_module.randmulti(5)) #20
エラーが出る場合
この時点で「ModuleNotFoundError」が出るという方は、モジュールファイルのディレクトリをもう一度確認してみてください。
このような状態だと実行ファイルの「test.py」とモジュールファイルが別々のディレクトリに収まっています。my_module.pyを実行ファイルと同じディレクトリに移動して試してみましょう。
ディレクトリを分ける
上記の場合とは逆に、「モジュール専用のディレクトリを作って管理したい」という場合、
- まずは実行ファイルと同じディレクトリに、新たにモジュールを入れるフォルダを作成します。
- 作成したフォルダに、モジュールファイルを入れます。
するとこんなディレクトリ構造になるはずです。
ルートフォルダ
├─moduleフォルダ
│ ├─my_module.py (モジュールファイル)
└─test.py (実行ファイル)
実行ファイルの1階層下にモジュールファイルがある状態です。このモジュールをインポートしてみましょう。
import module.my_module as m
m.greeting()
print(m.randmulti(5))
この場合、インポート文はフォルダ名から指定してあげる必要があります。as以降はあっても無くてもかまいませんが、関数の呼び出しなどが長くなってしまうので、ここでは別名でインポートしています。
フォルダ名とファイル名の間はドットが入ります。スペースではないので注意してください。
ちなみに「from module import mymodule as m」でも同じように呼び出すことが可能です。moduleフォルダに__init.py__を置いてパッケージとして扱う場合、このfromを用いた構文を使用しましょう。