閉じる

Pythonでモジュールを自作する方法|初心者がつまずくポイント全部解説

Pythonでコードを書いていると、「処理を分けて整理したい」「別ファイルの関数を使い回したい」と感じる場面が増えてきます。

そんな時に登場するのがモジュールです。

このページでは、Python初心者がつまずきやすいポイントをすべて拾いながら、モジュールを自作して活用できるようになるまでを、図解とサンプルコードたっぷりで丁寧に解説します。

モジュールとは何か

モジュールの基本概念とメリット

Pythonにおけるモジュールとは、Pythonコードをまとめた1つのファイル(.pyファイル)で、他のPythonコードからimportして再利用できる部品のことです。

関数やクラス、定数などを1つのファイルにまとめておき、必要なスクリプトから読み込んで使います。

モジュールを使う主なメリットは次のようなものです。

まず、コードを機能ごとに分割できるので、プログラム全体の見通しが良くなります。

計算処理は1つのモジュール、ファイル操作は別のモジュールといったように分けておくことで、後から見直したり修正したりする時に迷いにくくなります。

次に、同じ処理を何度も書かなくて済みます。

よく使う関数をモジュールにまとめておけば、別のプロジェクトでもimportするだけで再利用できます。

これは小さな自作スクリプトでも、業務で使う大きなアプリケーションでも非常に重要です。

また、テストもしやすくなります。

モジュール単位でテストコードを書くことで、ある機能だけを切り出して確認できるようになります。

結果的に、バグを見つけやすく、修正もしやすくなります。

スクリプトとの違いと役割

Pythonでは、よく「スクリプト」と「モジュール」という言葉が混ざって使われます。

どちらも.pyファイルであることが多いですが、役割が少し違います。

スクリプトは、基本的に「直接実行されることを前提に書かれたPythonファイル」です。

たとえば、ターミナルからpython main.pyのように起動し、メインの処理が上から順に実行されていきます。

自動化スクリプトや、ワンショットで動かす処理はこの形が多いです。

一方モジュールは、他のPythonコードからimportされて使われることを前提に設計されたファイルです。

内部には関数やクラスを定義しておき、メインの処理はあまり書かないか、書いたとしてもif __name__ == "__main__":というガードの中に限定するのが一般的です。

実際には、1つのファイルが「スクリプト」としても「モジュール」としても振る舞えるように書くことが多くありますが、考え方として「直接実行する主役はスクリプト」「機能を提供する部品はモジュール」と意識しておくと整理しやすくなります。

モジュールを自作する準備

モジュール自作に必要なPythonの基礎知識

モジュールを自作するために、高度な知識は必要ありませんが、最低限次のような基礎を理解しているとスムーズです。

まず、関数の定義と呼び出しができることが重要です。

モジュールの中身の多くは関数で構成されるためです。

defで関数を定義し、引数や戻り値を扱えるようになっておきましょう。

次に、クラスとオブジェクトの基本も知っておくと役立ちます。

必須ではありませんが、少し大きめのモジュールでは、クラスを使って機能をまとめることがよくあります。

さらに、変数スコープの概念も大切です。

モジュールレベルの変数(グローバル変数)と関数内のローカル変数の違いを理解しておくと、予期しない値の上書きを防ぎやすくなります。

そして、Pythonファイルの実行方法や、カレントディレクトリの概念も押さえておきたいポイントです。

モジュールがimportできない問題の多くは、このあたりの理解不足から来ています

モジュールを保存するファイル名のルール

モジュールは1ファイル1モジュールが基本で、そのファイル名がモジュール名になります。

たとえばmy_utils.pyというファイルはimport my_utilsで読み込めるようになります。

ファイル名を付ける時の主なルールと注意点を、文章で整理しておきます。

まず、ファイル名の末尾には.pyを付けます。

拡張子が違うとPythonからはモジュールとして認識されません。

次に、英数字とアンダースコアだけを使用するのが無難です。

ハイフン-やスペース、日本語名はトラブルの元になりやすいので避けることを強くおすすめします。

そして、数字から始まるファイル名も避けるべきです。

Pythonのモジュール名は、基本的に変数名(識別子)と同じルールに従うため、先頭を数字にすることはできません。

また、標準ライブラリや有名ライブラリと同じ名前を付けないことも重要です。

例えばrandom.pymath.pyといった名前にしてしまうと、本来の標準モジュールではなく自分のファイルが読まれてしまい、想定外のエラーが発生します。

この問題は後半でも詳しく扱います。

最後に、モジュールの役割がわかるような、意味のある名前を付けるとよいでしょう。

例えば、日付に関する処理ならdate_utils.py、ファイル入出力ならfile_io.pyといった名前にすると、後から見た時も迷いにくくなります。

作業用フォルダとファイル構成の考え方

モジュールを自作する時には、プロジェクト全体のフォルダ構成を少し意識しておくと、後から整理しやすくなります。

最もシンプルな形は、1つのフォルダの中に、実行用のスクリプトmain.pyと、自作モジュールmy_module.pyが並んでいる構成です。

この場合、main.pyからimport my_moduleと書くだけで、自作モジュールを読み込むことができます。

少し規模が大きくなってきたら、モジュールを専用のフォルダにまとめることもできます。

例えばutilsというフォルダを作り、その中に複数のモジュールファイルを置きます。

このフォルダは「パッケージ」と呼ばれる単位になり、import utils.calcのような形で読み込めるようになります。

この時、フォルダ内に__init__.pyという空ファイルを置くのが昔からの慣習です。

Python 3 では必須ではありませんが、パッケージだと明示する意味と、古いツールとの互換性のために、まだ使われることが多いです。

このファイルについては後ほど詳しく説明します。

モジュールの作り方とimportの基本

最初の自作モジュールを作成する手順

ここでは、最も基本的な自作モジュールを実際に作ってみます。

具体的なファイル名やコード例を示すので、その通りにフォルダを作って試してみてください。

まず、任意のフォルダ(例: my_project)を作り、その中にmy_module.pyというファイルを作成します。

このファイルの中に、簡単な関数を定義します。

Python
# my_module.py

# 挨拶メッセージを作成する関数
def make_greeting(name):
    """名前を受け取り、挨拶文を返す関数"""
    return f"こんにちは、{name}さん!"

# 足し算を行う関数
def add(a, b):
    """2つの数値を足し合わせて返す関数"""
    return a + b

次に、同じフォルダ内にmain.pyというファイルを作ります。

このファイルが実行用スクリプトになります。

Python
# main.py

# 自作モジュール my_module を読み込む
import my_module

def main():
    # my_module 内の make_greeting 関数を使う
    message = my_module.make_greeting("太郎")
    print(message)

    # my_module 内の add 関数を使う
    result = my_module.add(3, 5)
    print("3 + 5 =", result)

# このファイルが直接実行された時だけ main() を呼び出す
if __name__ == "__main__":
    main()

この2つのファイルを保存し、ターミナル(またはコマンドプロンプト)でフォルダに移動してから、次のように実行します。

Shell
python main.py

想定される出力は次のようになります。

実行結果
こんにちは、太郎さん!
3 + 5 = 8

このように、自作モジュールは、単に関数を定義した.pyファイルを作り、それを別のファイルからimportして使うだけで実現できます。

import文の書き方と動く仕組み

import文は、自作モジュールを含むPythonモジュールを読み込むための基本構文です。

最もシンプルな形はimport モジュール名で、先ほどの例のimport my_moduleがそれにあたります。

Pythonがimport my_moduleを実行すると、内部では次のような処理が行われています。

最初に、Pythonはsys.pathというリストに登録されているディレクトリを順番に調べていきます。

ここには、現在のフォルダ(カレントディレクトリ)や標準ライブラリのあるディレクトリ、仮想環境のサイトパッケージなどのパスが含まれています。

各ディレクトリについて、my_module.pymy_module/__init__.pyといったファイルが存在するかどうかを探します。

最初に見つかったものが、そのモジュールとして採用されます。

モジュールファイルが見つかると、そのファイルが1度だけ実行されます。

この実行によって定義された関数やクラス、変数がモジュールオブジェクトに格納され、importした側からmy_module.addのようにアクセスできるようになります。

ここで重要なのは、同じモジュールは原則として1回だけ読み込まれるという点です。

プログラムの途中で同じimport my_moduleを何度書いても、最初の1回だけが実行され、それ以降は既に読み込まれたモジュールオブジェクトが再利用されます。

from import構文の使い分け

モジュールを読み込む時には、importだけでなくfrom ... import ...という構文もよく使われます。

両者の違いと、使い分け方を理解しておくことが大切です。

先ほどの例を使って、2つの書き方を比較してみます。

Python
# パターン1: import モジュール名

import my_module

result = my_module.add(3, 5)  # モジュール名.関数名 で呼ぶ
Python
# パターン2: from モジュール名 import 名前

from my_module import add

result = add(3, 5)  # 関数名だけで呼べる

1つ目のパターンでは、モジュール全体を読み込み、そのモジュールに付けられた名前(ここではmy_module)からドット.でつないで関数を呼び出します。

名前の衝突を避けやすく、どのモジュールの関数かが明確にわかるので、基本的にはこちらの書き方をおすすめします。

2つ目のパターンでは、モジュール内の特定の名前だけを現在の名前空間に直接取り込みます。

コードが少し短くなり、頻繁に呼び出す関数では便利ですが、他のモジュールに同じ名前の関数がある場合に衝突する可能性が高まります。

そのため、使うモジュールが増えてきたら慎重に使い分ける必要があります。

また、from my_module import *という書き方もありますが、これはモジュール内の全ての公開名を一度に取り込んでしまうため、名前の衝突が起きやすく、どこから来た関数なのかコードから判断しづらくなります。

学習目的を除き、実務では基本的に避けることをおすすめします。

モジュール内で定義できる関数とクラスの例

モジュールの中には、関数だけでなくさまざまな要素を定義できます。

ここでは、代表的な要素である「関数」「クラス」「定数」をひとまとめにしたサンプルモジュールを作ってみます。

Python
# advanced_module.py

# モジュールレベルの定数
PI = 3.14159

# 円の面積を計算する関数
def circle_area(radius):
    """半径から円の面積を計算して返す"""
    return PI * (radius ** 2)

# 円を表すクラス
class Circle:
    """半径を持つ円を表現するクラス"""

    def __init__(self, radius):
        self.radius = radius

    def area(self):
        """自身の半径から面積を計算する"""
        return circle_area(self.radius)

    def circumference(self):
        """自身の半径から円周の長さを計算する"""
        return 2 * PI * self.radius

# モジュールを単体実行した時だけ動くテストコード
if __name__ == "__main__":
    c = Circle(3)
    print("半径3の円の面積:", c.area())
    print("半径3の円周:", c.circumference())

このadvanced_module.pyを直接実行すると、モジュール内のテストコードが動きます。

Shell
python advanced_module.py
実行結果
半径3の円の面積: 28.27431
半径3の円周: 18.84954

一方、別のファイルからこのモジュールをimportすると、if __name__ == "__main__":以下のテストコードは実行されず、関数やクラスだけが利用できる状態になります。

これは次のセクションで扱う「実行ファイルとモジュールを分けるベストプラクティス」にもつながる重要な書き方です。

初心者がつまずくポイントと対処法

モジュールがimportできない時の原因と対策

自作モジュールを使い始めた初心者が最初にぶつかりやすいのが、ModuleNotFoundErrorImportErrorです。

適切にファイルを書いたはずなのにimport my_moduleが失敗してしまう場合、原因はある程度パターン化されています。

最も多いのは、実行している場所とファイルが存在する場所(パス)がずれているケースです。

ターミナルでPythonを起動する前に、きちんとプロジェクトフォルダに移動しているかを確認しましょう。

また、VS Codeや他のIDEを使っている場合でも、「実行時の作業ディレクトリ」が意図したフォルダになっているかを設定で確認する必要があります。

次に多いのが、モジュール名とファイル名の不一致です。

例えばmy-module.pyのようにハイフンを含んでいると、import my-moduleのようには書けません。

この場合、ファイル名をmy_module.pyに修正するのが正しい対応になります。

さらに、標準ライブラリやインストール済みパッケージと同名のモジュールを作ってしまったことが原因で、importの対象が自作モジュールではなく別物になっていることもあります。

この問題については、後の「同名ファイルやフォルダでモジュールが読み込めない問題」で詳しく説明します。

パス(PYTHONPATH)とカレントディレクトリの理解

Pythonがモジュールを探す場所は、sys.pathというリストで決まっています。

このリストには、モジュール検索の対象となるディレクトリが順番に格納されています。

自作モジュールを正しくimportするには、この仕組みをざっくり理解しておくことが非常に大切です。

Python対話モードやスクリプト内で次のように打ち込むと、実際のパスを確認できます。

Python
import sys

for p in sys.path:
    print(p)

出力結果の一例は次のようになります。

(環境によって異なります)

実行結果
/path/to/your/project
/usr/local/lib/python3.12
/usr/local/lib/python3.12/site-packages
...

最初の行には、通常「カレントディレクトリ」または「実行中スクリプトがあるディレクトリ」が入ります。

カレントディレクトリとは、ターミナルやIDEが「今作業している場所」として認識しているフォルダです。

多くの初心者トラブルは、このカレントディレクトリが意図しているフォルダと違っていることで発生します

また、PYTHONPATHという環境変数にディレクトリを追加すると、そのディレクトリもモジュール検索パスに含めることができます。

ただし、初心者のうちは無理にPYTHONPATHをいじるよりも、「自作モジュールと実行スクリプトを同じフォルダか、その下のフォルダに置く」というルールで始めるのが安全です。

同名ファイルやフォルダでモジュールが読み込めない問題

モジュール名の衝突も、初心者だけでなく経験者もよくハマるポイントです。

特に、標準ライブラリと同じ名前のファイルやフォルダをプロジェクト内に作ってしまうと、思わぬエラーが発生します。

例えば、次のような構成を考えてみます。

  • random.py(自作)
  • main.py

この状態でmain.pyの中からimport randomと書くと、本来は標準ライブラリのrandomモジュールを読み込みたいのに、Pythonはカレントディレクトリのrandom.pyを先に見つけてしまいます。

その結果、標準ライブラリの関数を呼び出そうとしてエラーになることがあります。

この問題を避けるためには、標準ライブラリと同名のファイルを作らないことが基本です。

標準ライブラリのモジュール名は公式ドキュメントに一覧がありますが、すべてを暗記する必要はありません。

何か標準ライブラリをimportして使っている時、その名前を自作ファイルに使わないよう意識するだけでもかなり防げます。

もし既に同名ファイルを作ってしまった場合は、ファイル名を変更し(例えばmy_random_utils.pyなどにする)、それに合わせてimport文も書き換えます。

また、__pycache__フォルダの中にキャッシュされた古いモジュールが残っていると、動作に影響することもあるので、必要に応じて削除しておきましょう。

相対インポートと絶対インポートの違いと注意点

プロジェクトが少し大きくなると、フォルダを切ってパッケージとして構成することが増えてきます。

この時によく話題になるのが、絶対インポート相対インポートです。

絶対インポートとは、プロジェクトのルート(トップレベル)からの完全なパスでモジュールを指定する方法です。

例えば、次の構成を考えます。

  • my_app/
    • main.py
    • utils/
      • __init__.py
      • calc.py
      • string_tools.py

この時、main.pyからcalcモジュールを読み込むには、通常from utils import calcのように書きます。

これが絶対インポートです。

一方、相対インポートは、現在のモジュールファイルの位置からの相対的な位置を...で指定する方法です。

例えば、calc.pyの中から同じフォルダにあるstring_tools.pyを読み込むには、次のように書けます。

Python
# calc.py 内

# 相対インポートの例
from . import string_tools

ただし、相対インポートには初心者がハマりやすい落とし穴があります。

相対インポートは「パッケージ内のモジュール」同士で使うことが前提であり、そのモジュールファイルを単体で直接実行しようとするとエラーになることが多いです。

そのため、最初のうちは絶対インポートを基本として使い、パッケージ構成に慣れてきてから相対インポートを検討するというスタンスがおすすめです。

__init__.pyの意味とパッケージとの関係

__init__.pyは、Pythonパッケージにおいて特別な意味を持つファイルです。

ファイル名は固定で、先頭と末尾にアンダースコアが2つずつ付いています。

Python 2 の時代には、あるフォルダを「パッケージ」として扱うためには、そのフォルダ内に__init__.pyが必須でした。

Python 3 では、このファイルがなくても「名前空間パッケージ」として扱われるため、物理的にはなくてもパッケージのように動作させることができます。

しかし実務では、次のような理由から今でも__init__.pyを置くことが多いです。

1つ目の理由は、「ここはPythonパッケージです」と人間にわかりやすく伝えるためです。

特に大規模プロジェクトでは、単なるフォルダとパッケージフォルダを区別できることが重要になります。

2つ目の理由は、パッケージをimportした時の初期処理や、エクスポートする名前の制御を行えることです。

__init__.pyの中でfrom .calc import *のように書いておくと、from utils import *とした時にどの名前が公開されるかを制御できます。

また、__all__というリストを__init__.pyの中に定義しておくと、パッケージからfrom utils import *した時にインポートされる名前を明示的に指定することもできます。

実行ファイルとモジュールを分けるベストプラクティス

最後に、自作モジュールを活かすための「実行ファイルとモジュールの分け方」について整理します。

Pythonコードが増えてきたら、1つの巨大なスクリプトにすべてを書かず、「実行用」と「部品用」をしっかり分ける習慣を付けることが大切です。

基本的な考え方としては、次のような形が理想的です。

まず、実行ファイル(エントリポイント)は最小限にすることです。

例えばmain.pyには、コマンドライン引数の処理や、アプリケーションの起動処理だけを書き、実際のロジックはすべて別モジュールに切り出します。

Python
# main.py

from app.core import run_app

def main():
    # アプリケーション全体を起動する関数を呼び出すだけ
    run_app()

if __name__ == "__main__":
    main()

次に、機能ごとにモジュールやパッケージを分けることです。

データベース関連の処理はdb.py、ファイル処理はfile_utils.pyといった具合に、自然な単位でファイルを分けていきます。

これにより、テストしやすく、再利用しやすい構成になります。

また、各モジュールは「他からimportされること」を想定して設計します。

テストコードはif __name__ == "__main__":のブロックに入れておくと、モジュールとして読み込んだ時には実行されません。

これは、先に示したadvanced_module.pyの例でも確認した書き方です。

このような分割を意識することで、Pythonプロジェクトは自然と「モジュール指向」の構造になり、後から機能を追加したり、別のプロジェクトに一部機能を持っていったりするのが格段に楽になります。

まとめ

自作モジュールは、Pythonプログラムを整理し、再利用性と保守性を高めるための基本的な仕組みです。

本記事では、モジュールの概念から始め、ファイル名のルールやフォルダ構成、importの動作、__init__.pyやパッケージの関係まで、一通りの流れを解説しました。

初心者がつまずきやすい「importできない」「名前が衝突する」といった問題も、パスと名前空間の仕組みを理解すれば必ず解決できます。

まずは小さな自作モジュールを作り、実行ファイルと分ける練習から始めてみてください。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!