Pythonでモジュールを単体で実行すると、その中のテストコードも実行されてしまうことがある。たとえば、以下のような温度変換モジュール candf.py を作成したとする:
# candf.py
def c2f(celsius):
return celsius * 9 / 5 + 32
def f2c(fahrenheit):
return (fahrenheit - 32) * 5 / 9
# テストコード
print("テストデータ:0 摂氏度 = %.2f 華氏度" % c2f(0))
print("テストデータ:0 華氏度 = %.2f 摂氏度" % f2c(0))
このモジュールを別ファイル demo.py からインポートして使うと:
import candf
print("32 摂氏度 = %.2f 華氏度" % candf.c2f(32))
print("99 華氏度 = %.2f 摂氏度" % candf.f2c(99))
実行結果にはモジュール内のテスト出力も含まれてしまう。これを避けるためには、if __name__ == '__main__': を使用する:
# candf.py(修正版)
def c2f(celsius):
return celsius * 9 / 5 + 32
def f2c(fahrenheit):
return (fahrenheit - 32) * 5 / 9
if __name__ == '__main__':
print("テストデータ:0 摂氏度 = %.2f 華氏度" % c2f(0))
print("テストデータ:0 華氏度 = %.2f 摂氏度" % f2c(0))
これにより、モジュールが直接実行されたときのみテストコードが実行されるようになる。
モジュールが見つからないエラーの対処法
ModuleNotFoundError は、Pythonが指定されたモジュールを検索パスから見つけられなかった場合に発生する。Pythonは以下の順序でモジュールを検索する:
- 現在のディレクトリ
PYTHONPATH環境変数に設定されたディレクトリ- Pythonの標準ライブラリディレクトリ
これらのパスは sys.path に格納されている。モジュールを正しくインポートするための主な方法は以下の3つである。
1. sys.path に一時的にパスを追加
import sys
sys.path.append(r'D:\python_module')
import hello
hello.say()
この方法はスクリプト実行中に有効だが、プロセス終了後は無効になる。
2. モジュールを標準パスに配置
site-packages ディレクトリ(例: D:\python3.6\lib\site-packages)にモジュールを置くことで、すべてのスクリプトから利用可能になる。
3. PYTHONPATH 環境変数の設定
Windows:
システム環境変数またはユーザ環境変数に PYTHONPATH を追加し、値として .;D:\python_module を設定する(複数パスはセミコロン区切り)。
Linux / macOS:
~/.bash_profile または ~/.zshrc に以下を追記:
export PYTHONPATH=".:/home/username/python_module"
その後、source ~/.bash_profile を実行して反映させる。
モジュールのインポートの本質
import 文はモジュール全体をメモリに読み込み、実行し、その内容を module 型のオブジェクトとして名前空間にバインドする。たとえば:
# fk_module.py
print("this is fk_module")
name = 'fkit'
def hello():
print("Hello, Python")
import fk_module
print(type(fk_module)) # <class 'module'>
一方、from ... import ... はモジュールを実行した上で、指定されたメンバーのみを現在の名前空間に取り込む:
from fk_module import name, hello
print(name) # fkit
# print(fk_module) # NameError(モジュール自体はインポートされていない)
また、同じモジュールを複数回インポートしても、実際の実行は1回のみ行われる。これは循環インポートを防ぐ仕組みでもある。
__all__ の役割
from module import * の際に公開するメンバーを制限するには、モジュール内で __all__ を定義する:
# demo.py
def say():
print("人生苦短、我学Python!")
def CLanguage():
print("C语言中文网")
def disPython():
print("Python教程")
__all__ = ["say", "CLanguage"]
from demo import *
say() # OK
CLanguage() # OK
disPython() # NameError
ただし、import demo や from demo import disPython のように明示的にインポートする場合は、__all__ の影響を受けない。
パッケージの作成と利用
パッケージは複数のモジュールを含むディレクトリであり、Python 3.3以降では __init__.py がなくてもパッケージとして認識されるが、初期化コードを実行したい場合は依然として必要である。
例として、以下のような構造のパッケージ my_package を作成する:
my_package/ ├── __init__.py ├── module1.py └── module2.py
__init__.py でサブモジュールを公開することで、利用側の記述を簡潔にできる:
# my_package/__init__.py
from .module1 import display
from .module2 import CLanguage
これにより、以下のように簡単に利用できる:
import my_package
my_package.display("Hello")
lang = my_package.CLanguage()
lang.display()
モジュール内容の確認方法
モジュールに含まれるメンバーを調べるには、dir() 関数や __all__ 属性を使用する:
import string
# 特殊メソッドを除いた公開メンバー
print([name for name in dir(string) if not name.startswith('_')])
# __all__ が定義されていれば
print(string.__all__)
さらに詳細な情報を得るには、help() 関数や __doc__ 属性を利用する:
help(string.ascii_letters)
print(string.capwords.__doc__)
これらにより、モジュールの機能や使い方をインタラクティブに確認できる。