どうも、こんにちは!
Pythonのライブラリを使っている時ってimport対象をついつい省略するために*を使ってしまうんですよね。。
とっても便利だけど、これって何をしてるんだろう・・?
考えてみると意外と難しいですよね。
実を言うと、答えはモジュールかパッケージかの違いと__all__が握っているんです!
おさらいとして
モジュールは2通りの呼び出し方法があります。
忘れてしまった方は以下の記事で復習できますよ!
その2通りの呼び出しの内の1つが以下のようなコードです。
import foo from object
これのobjectを*(ワイルドカード)にすることで全てのオブジェクトを使えるといいましたが、厳密に言うと違います。
以下の4パターンになります。
- __all__がある場合:モジュールの場合
- __all__がある場合:パッケージの場合
- __all__がない場合:モジュールの場合
- __all__がない場合:パッケージの場合
それではそれぞれみていきましょー!
__all__がある場合
__all__で記述されている内容だけがインポートされます。
ディレクトリの構成は次のように考えてみましょう。
.
├── caller.py
└── package
├── __init__.py
├── moduleA.py
└── moduleB.py
コードは以下になります。
モジュールの場合
モジュールの中で__all__にimportされるオブジェクトがlistとして書いてあります。
今回の例でいうとmoduleB.pyを実行してみましょう。
dir()は現在定義されているオブジェクトを表示する関数です。
実行すると以下のように表示されます。
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__','__loader__', '__name__','__package__', '__spec__','test1']
__all__で定義したtest1の関数だけがここに格納されています!
パッケージの場合
パッケージの__init__.pyの中に__all__にインポートされるモジュールがlistで書いてあります。
それではmoduleB.pyを実行してみましょう。
['__annotations__', '__builtins__', '__cached__','__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'moduleA']
__all__がない場合
これはモジュールかパッケージかによって動作が異なりますので注意してください
ディレクトリの構成は先ほどと同じです。
.
├── caller.py
└── package
├── __init__.py
├── moduleA.py
└── moduleB.py
コードは以下になります。
モジュールの場合
アンダースコア(_)で始まる名前を除く全てのオブジェクトを全てインポートします。
アンダースコアは変数の中でしか使いませんよっていう宣言ですので、使ってもいいやつは全てインポートされます(こういった変数をプライベート変数といいます)。
先ほどと同様にmoduleB.pyを実行してみましょう。
実行すると以下のように表示されます。
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'test1', 'test2']
_privateを除くオブジェクトがインポートされていますね!
パッケージの場合
fromで指定したパッケージのみをインストールします
それではcaller.pyを実行してみましょう。
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
一つもモジュールはインポートされていないことがわかります。
これは直感的ではないですよね。
ワイルドカード使ってんだから全部とってきてよ!!って感じですよね 笑
ですが、大きなパッケージになると相当数のモジュールやサブパッケージが含まれています。
それを処理するのはかなり時間がかかるので、こういった実装になっているのです。
import *は意識する必要はほぼない
普通に使う分には問題ないのです!
開発者としてパッケージを作成して世の中にリリースする場合は考慮すればいいって感じですね。
ですが、この記法はあまりよくないです。
単純にいって、使わないオブジェクトを組み込むわけですからね。必要ないものは極力ないほうがソースコードって読みやすいんですよ。
ですので使うのはインタープリターでの実行だけに留めておきましょう。
ただ、こういう書き方もあるのだという認識で大丈夫です。
以上になります。この記事であなたがよりよいPython生活を送れることを祈ってます!