Python におけるモジュールとパッケージのインポート

PythonBeginner
オンラインで実践に進む

はじめに

この実験(Lab)では、Python におけるモジュールとパッケージを扱うことで、コードの整理と再利用の基本を学びます。まず、Python モジュールとは何か、そしてそれが直接実行される場合とインポートされる場合とで、その実行動作がどのように変化するかを理解することから始めます。

次に、モジュールのコードをプログラムに取り込む主要な 2 つの方法、すなわち、モジュール全体をロードするための import 文と、特定の関数や変数をロードするための from...import 文を練習します。最後に、関連するモジュールをパッケージとして構造化し、整理されスケーラブルなプロジェクトを作成する方法を学びます。すべてのコーディングは、Python ファイルとターミナルを使用して、WebIDE 内で行われます。

Python モジュールの理解

Python におけるモジュールとは、単に .py 拡張子を持つ Python コードを含むファイルのことです。モジュールを使用することで、コードを論理的に整理でき、管理や再利用が容易になります。モジュール内で定義された関数、クラス、変数は、他のスクリプトで使用できます。

WebIDE には、左側にファイルエクスプローラーが表示されます。実験環境では、すでに ~/project ディレクトリ内に hello.py というファイルが作成されています。

まず、hello.py を開いてその内容を確認してください。以下のコードが含まれているはずです。

print("This code runs on import or direct execution.")

if __name__ == "__main__":
    print("This code runs ONLY when the script is executed directly.")

if __name__ == "__main__": ブロックは、Python における特別な構造です。__name__ 変数は、現在のモジュールの名前に評価される組み込み変数です。Python スクリプトがコマンドラインから直接実行される場合、その __name__ は文字列 "__main__" に設定されます。この if 文により、ファイルがメインプログラムとして実行された場合にのみ実行されるコードを記述でき、他のモジュールによってインポートされた場合には実行されないようにできます。

これを実際に見てみましょう。WebIDE でターミナルを開き、hello.py スクリプトを直接実行します。

python3 hello.py

両方の print 文が実行されるため、以下の出力が表示されます。

This code runs on import or direct execution.
This code runs ONLY when the script is executed directly.

これは、スクリプトが実行されるメインプログラムである場合の動作を示しています。次のステップでは、これをモジュールとしてインポートした場合に何が起こるかを確認します。

import ステートメントを使用したモジュールのインポート

モジュールを使用する最も一般的な方法は、import 文を使用してそれをインポートすることです。これにより、モジュール内のすべてのコードが現在のスクリプトで利用可能になります。

ファイルエクスプローラーには、main.py という名前の空のファイルがあります。これが、この実験(Lab)の残りの部分で使用するメインスクリプトになります。

main.py を開き、hello モジュールをインポートするために次の行を追加します。

import hello

print("The main.py script has finished.")

ファイルを保存します。次に、ターミナルから main.py を実行します。

python3 main.py

出力を注意深く観察してください。

This code runs on import or direct execution.
The main.py script has finished.

hello.py からの最初の print 文のみが実行されたことに注目してください。if __name__ == "__main__": ブロック内のコードはスキップされました。これは、main.pyhello をインポートするとき、hello.py のコンテキスト内での __name__ 変数が "__main__" ではなく、モジュールの名前である "hello" に設定されるためです。この機能は、インポート時に望ましくない副作用を発生させない再利用可能なモジュールを作成するために不可欠です。

次に、print 文以上のものを含むモジュールを扱ってみましょう。module_a.py ファイルを開きます。これには、変数、関数、クラスが含まれています。

PI = 3.14159

def greet(name):
 print(f"Hello, {name} from module_a!")

class Calculator:
    def add(self, x, y):
        return x + y

main.py を変更して module_a をインポートし、そのメンバーを使用します。インポートされたモジュールのメンバーにアクセスするには、module_name.member_name という構文を使用します。

main.py の内容を以下に置き換えます。

import module_a

## Access the PI variable
print(f"The value of PI is {module_a.PI}")

## Call the greet function
module_a.greet("LabEx")

## Create an instance of the Calculator class and use its method
calc = module_a.Calculator()
result = calc.add(5, 3)
print(f"5 + 3 = {result}")

ファイルを保存して実行します。

python3 main.py

出力は次のようになります。

The value of PI is 3.14159
Hello, LabEx from module_a!
5 + 3 = 8

これは、import 文がモジュール全体をロードし、モジュールの名前をプレフィックスとして使用してその内容にアクセスする方法を示しています。

from...import を使用した特定のオブジェクトのインポート

モジュールから特定のアイテムのみが必要な場合があります。from...import 文を使用すると、特定の関数、クラス、または変数を現在のスクリプトのネームスペースに直接インポートできます。これにより、module_name. プレフィックスなしでそれらを使用できるようになります。

このインポート方法を使用するように main.py を変更しましょう。module_a 全体をインポートする代わりに、PI 変数と greet 関数のみをインポートします。

main.py を次のコードに更新します。

from module_a import PI, greet

## Access PI and greet directly without the module prefix
print(f"The value of PI is {PI}")
greet("World")

ファイルを保存し、ターミナルから実行します。

python3 main.py

出力は次のようになります。

The value of PI is 3.14159
Hello, World from module_a!

ご覧のとおり、PIgreet は直接使用されています。ただし、インポートしなかったもの(例:Calculator クラス)にアクセスしようとすると、エラーが発生します。

今、それを試してみましょう。main.py の末尾に次の行を追加します。

calc = Calculator()
print(calc.add(10, 20))

スクリプトを再度実行します。

python3 main.py

今度は、スクリプトは NameError で失敗します。

The value of PI is 3.14159
Hello, World from module_a!
Traceback (most recent call last):
  File "/home/labex/project/main.py", line 7, in <module>
    calc = Calculator()
NameError: name 'Calculator' is not defined

このエラーは、from...import 文で指定されたオブジェクトのみが現在のネームスペースに取り込まれることを確認しています。この方法はコードの可読性を高めることができますが、異なるモジュールから同じ名前のオブジェクトをインポートすると、名前の競合のリスクも高まります。

次のステップに進む前に、エラーを引き起こした 2 行を main.py から削除してください。

Python パッケージの理解と使用

プロジェクトが大きくなるにつれて、関連するモジュールを単一のディレクトリ階層に整理したくなることがあります。これがパッケージの役割です。パッケージとは、__init__.py という名前の特別なファイル(空でも構いません)を含むディレクトリのことです。このファイルの存在により、Python はそのディレクトリをパッケージとして扱います。

module_a を格納するためのパッケージを作成しましょう。

まず、~/project ディレクトリ内に my_package という名前の新しいディレクトリを作成します。これは、ファイルエクスプローラーで右クリックし、「新規フォルダー」を選択することで実行できます。

mkdir my_package

次に、新しく作成した my_package ディレクトリ内に必須の __init__.py ファイルを作成します。

touch my_package/__init__.py

次に、module_a.pymy_package ディレクトリに移動します。ファイルエクスプローラーでファイルをドラッグ&ドロップできます。

mv module_a.py my_package/

プロジェクトの構造は次のようになります。

~/project/
├── main.py
├── hello.py
└── my_package/
    ├── __init__.py
    └── module_a.py

このパッケージ構造を設定したら、main.py スクリプトでの module_a のインポート方法を更新する必要があります。パッケージ内のモジュールをインポートするには、package_name.module_name のようなドット付きモジュール名を使用します。

main.py を開き、my_package.module_a から greet 関数をインポートするように変更します。

from my_package.module_a import greet

greet("Package")

ファイルを保存し、実行します。

python3 main.py

次の出力が表示されるはずです。

Hello, Package from module_a!

これは、パッケージ内のモジュールから特定のオブジェクトをインポートする方法を示しています。あるいは、モジュール自体をインポートすることもできます。

## Alternative import style
import my_package.module_a

my_package.module_a.greet("Alternative")

パッケージは、ライブラリやフレームワークなどの大規模なコードベースを明確で保守しやすい構造に整理するための強力なツールです。

まとめ

この実験(Lab)では、Python におけるコード整理の基本的な概念を学びました。まず、モジュールとは何か、そして再利用可能なコードを作成するための if __name__ == "__main__": ブロックの目的を理解することから始めました。次に、import module_name 構文を使用してモジュールをインポートし、ドット表記(ドット演算子)でそのメンバーにアクセスする練習をしました。

さらに、from...import 文を探求し、モジュールから特定のオブジェクトをスクリプトのネームスペースに直接取り込む方法を学びました。最後に、__init__.py ファイルを持つディレクトリを作成することで関連モジュールをパッケージに構造化する方法、およびそのパッケージからインポートする方法を学習しました。これらのスキルは、クリーンで整理され、スケーラブルな Python アプリケーションを作成するための基礎となります。