Python __all__について
なんか,役に立つのか立たないのか微妙なところになってきた.
__all__は,モジュールの外に公開するかしないかを決める,C言語でもがんばって関数の公開,非公開を無理矢理記述するように,結局シンボルテーブルを変更する,,,らしい.
その動作を知るためにサンプルを書いてみる.まず,テスト用のパッケージを書く.
#hoge/hoge.py def h1(a): return a; def h2(a): return a+1;
上の関数をもつ,hogeパッケージ(hogeモジュールのみ)を作ってみる.
んで,これを呼び出す部分.
#hogemain.py from hoge.hoge import h1, h2; print h1(2); print h2(2);
$ python hogemain.py 2 3
まぁいいですね.
では,__all__を使ってみる.例えば,h2を公開したくない!と言う場合.
#hoge/hoge.py __all__ = ['h1']; def h1(a): return a; def h2(a): return a+1;
$ python hogemain.py Traceback (most recent call last): File "hogemain.py", line 2, in <module> from hoge.hoge import h1, h2; ImportError: cannot import name h2
これは,「明示的に使う関数を宣言する」というPythonのお勧めするクリーンなコードだったため,importステートメントではねてくれています.しかし,現実は,hogemain.pyは以下のように書かれる可能性も.
from hoge.hoge import *; ##from hoge.hoge import h1, h2; print h1(2); print h2(2);
するとどうなるか,といいますと,
Traceback (most recent call last): File "hogemain.py", line 5, in <module> print h2(2); NameError: name 'h2' is not defined
先ほどとはエラーの出る箇所が替わりました.これでうまくh2を隠蔽できています.h2をシンボルテーブルにのせない方法はもう一つあって,__all__を書かずに,関数名を_h2とする方法です.こちらのほうがソースコードの途中をみても,その関数の使途がわかるので好きかも.
ちなみに,__all__法はfrom (module) import * 以外,たとえばimport (module)では無視されるそうです.
import hoge.hoge; print hoge.hoge.h1(2); print hoge.hoge.h2(2);
$ python hogemain.py 2 3
こちらも__all__の指定はそのままなのですが,h2は呼べちゃっています.hoge.hogeという名前空間があるため,特に隠蔽の必要がないのですね.fromを使った,自分の名前空間へのロードの場合のみ作用する,という仕様みたいです.
さて,使いどころですが,モジュールから出すシンボルが多いとすべてのリストアップは厄介です.個人的には_を使う方が良い気がしています.あとは,パッケージ内のモジュール名を__init__.pyに__all__で記述しておいて,一部隠蔽する,という使い方もあるみたいです.