Open9
pythonのモジュールシステムをさらう
python、特にモジュール周りが全然わからないので公式チュートリアルを見ながらまとめる
- モジュールとは
- 定義をファイルに書いておき、他のモジュールや main モジュール(=実行のトップレベル) に importできるもの
- モジュールは Python の定義や文が入ったファイル。ファイル名はモジュール名に接尾語 .py がついたもの。(モジュールの中では、モジュール名を
__name__
で取得可能)
- モジュール内の実行文
- モジュールの中に、初期化目的で実行文を入れることができる。この実行文は、初めてインポートされたときに一度だけ実行される
- モジュール内では、ユーザのグローバル変数との衝突は心配しなくて良い
- importの書き方
-
from fibo import fib, fib2
: 使いたいものだけインポート -
from fibo import *
: 非推奨。 fiboモジュールの中の未知の名前が読み込まれ、定義済みの名前を上書きしてしまう可能性がある -
import fibo as fib
: モジュール名を任意の名前に変えて取り扱える
-
モジュールをスクリプトとして実行する
- モジュールは、
python fibo.py
みたいな形でも実行できる。この場合、__name__
はモジュール名ではなく__main__
になる。- つまり、
if __name__ == "__main__":
っていうブロックを付け加えて、そこに処理を書けば、スクリプトとしても実行できる。 - これは、モジュールに便利なUIを提供したり、テストのために使われたりする。
- つまり、
モジュール検索パス
- モジュールを探す優先順位 (
import spam
というインポートをしたとき)- まず、ビルトインモジュールを探す
- 次に、sys.pathにあるディレクトリのリストから
spam.py
を探す。- sys.pathはどこか
- 入力されたスクリプトのあるディレクトリ(or カレントディレクトリ)
- PYTHONPATH
- インストール方法によって異なるが、
site-packages
的なところ。(<- npmでいうところのグローバルインストールしたパッケージ的な?)
- 一応、sys.pathをpythonプログラム内で書き換えることもでできるが、多くの場合混乱の元。
- sys.pathはどこか
「コンパイル」されたpythonファイル
- モジュール読み込みを高速化するため、pythonはコンパイル済みモジュールを
__pycache__
ディレクトリの.pyc
ファイルにキャッシュする - ちなみに、pycファイルの実行は、pyファイルの実行に比べて高速化しない
- あくまで読み込みにかかる時間だけ
dir()
関数
-
dir(<モジュール名>)
とすると、モジュール内にどんな名前が定義されているか、一覧を取得できる。(引数なしだと現在のモジュール)
パッケージ
- パッケージ = モジュールの名前空間を "ドット付きモジュール名" を使って構造化する手段
- 例えば、
import A.B
みたいに、AというパッケージのサブモジュールBをインポートできる。- 複数モジュールからなるパッケージをつくるときに有用
- ファイルを含むディレクトリをパッケージとして認識させるには、
__init__.py
が必要。- これが必要な理由は、何でもかんでもパッケージとみなしてしまうと、
string
みたいな名前のディレクトリがあったときに、それが意図せずパッケージとしてみなされてしまい、他のパッケージやモジュールが隠蔽されてしまうから - 簡単なケースでは
__init__.py
は空でもよいが、初期化処理を書いたりもできる。
- これが必要な理由は、何でもかんでもパッケージとみなしてしまうと、
パッケージのインポート
-
importの書き方 (
sound.efects.echo
というモジュール内のechofilter
関数を使いたいとする)-
import sound.effects.echo
: 関数の利用時にsound.effects.echo.echofilter
と書かないといけない -
from sound.effects import echo
: 関数の利用時にecho.echofilter
と書ける -
from sound.effects.echo import echofilter
: 関数の利用時にechofilter
と書ける -
from sound.effects import *
: 非推奨。__init__.py
に__all__ = ["echo", ...]
みたいな定義が書いてあれば、そのモジュールが読み込まれる。書いてなければ、sound.effects
のすべてのサブモジュールをインポートしない。
-
-
なお、
from xxx
と書くときは、xxxはパッケージもしくはモジュールじゃないといけないので注意(クラスとか関数は不可) -
from .. import formats
みたいに相対importもできる (ただし、現在のモジュール名がベースになっていることに注意)