importしたら何が起きているの?
分かったようで分からない。
使えるけどよく知らない。
そんなimportしたら何が起きるのかを調べてみました。
動作環境(バージョン)
ipython : 6.2.1
python: Python 3.6.4 :: Anaconda, Inc.
カレントディレクトリに下記のファイルを置いています。
def hoge():
print("ほげメソッド!")
print("ほげぇ!")
def fuga():
print("ふがメソッド!")
if __name__ == '__main__':
print("ふがぁ!")
importって何をしてるの?
そもそもimport hoge
が何をしているかというとhoge.pyを実行しているだけです。
- #以下は解説コメントなので実際には表示されません。*
In [1]: import hoge
ほげぇ! # hoge.pyファイルを実行するのでprint("ほげぇ!")が実行される
In [2]: hoge.hoge()
ほげメソッド! # 定義されたメソッドはhoge.メソッド名で実行できる。
In [9]: type(hoge)
Out[9]: module # hogeさんはメソッドクラス
なんのことはありません。hoge.pyを読み込んでメモリに展開し、hoge.xxx()の形でhoge.py内に記述した変数やメソッドにアクセスできるようになっただけです。
csvとかrequestsとかのファイルは?作った覚えないんだけど?
csvなど標準モジュールはpythonをインストールされるディレクトリの近くに配置されています。具体的にはimport module
したあと、module.__file__
で絶対パスが分かります。
In [11]: import csv
In [12]: csv.__file__
Out[12]: '/Users/user/.pyenv/versions/anaconda3-5.1.0/lib/python3.6/csv.py'
出力で出てきたファイルを開くとちゃんとpythonで記述されていることが分かります。
In [15]: import numpy
In [16]: numpy.__file__
Out[16]: '/Users/user/.pyenv/versions/anaconda3-5.1.0/lib/python3.6/site-packages/numpy/__init__.py'
また外部モジュールで多いのが読み込むファイルが__init__.pyになっていることがあります。
この場合は__init__.py
を見れば分かりますが、そのディレクトリ上にモジュール群となるpyファイルがありそれらをimportしています。つまり全部一つ一つimportするのは大変だからまとめてimportしてくれます。
importするファイルはどうやって見つけるの?
sys.path
に記述された場所を探します。
基本的には
- カレントディレクトリ
- 標準モジュールの置き場
- pip installしたときの保存先
は何もしなくても読み込み対象のディレクトリとして指定されています。
In [19]: import sys
In [20]: sys.path
Out[20]:
['',
'/Users/user/.pyenv/versions/anaconda3-5.1.0/bin',
'/Users/user/.pyenv/versions/anaconda3-5.1.0/lib/python36.zip',
'/Users/user/.pyenv/versions/anaconda3-5.1.0/lib/python3.6',
'/Users/user/.pyenv/versions/anaconda3-5.1.0/lib/python3.6/lib-dynload',
'/Users/user/.pyenv/versions/anaconda3-5.1.0/lib/python3.6/site-packages',
'/Users/user/.pyenv/versions/anaconda3-5.1.0/lib/python3.6/site-packages/aeosa',
'/Users/user/.pyenv/versions/anaconda3-5.1.0/lib/python3.6/site-packages/IPython/extensions',
'/Users/user/.ipython']
もし他のディレクトリを読み込みの対象にしたければ.bash_profileなどに
export PYTHONPATH="${PYTHONPATH}:/読み込みたいディレクトリのフルパス/"
を追記して再読み込みすれば反映されます。
if name == "main":って何?
そのファイルそのものを実行したときだけ実行されるブロックになります。
まずターミナル上でfuga.pyを実行してみましょう。
python $python fuga.py
ふがぁ
次にipythonでfugaをインポートしてみます。
In [1]: import fuga
# 何も表示されない
このように直接そのファイルを実行したときは実行され、
インポートしたときは実行されません。
なぜこのような書き方がされるのでしょうか?
たとえばturtleモジュールはこのif __name__ == "__main__":
のブロックにデモの記述があり、python turtle.pyとするとカメさんが元気よく歩き出します。
ただあくまでもデモ用なのでimport turtle
のときは実行しないようにしています。
しかしいくらカメさんが可愛いとといってもimportのたびに動かれてはウンザリしてしまうでしょう。
このようにモジュールとして読み込むときには実行して欲しくないデモやテストなどの処理を書いておける書き方になります。
if __name__ == "__main__":
の目的は分かったけどこの気持ち悪い書き方は何?
__name__
などちょっと見慣れないものが入っていますが、ただのif文です。
"__main__"
は見ての通り文字列なので入門書でよく見る
if student == "Ken":
と同じです。
え?__name__
なんて宣言した覚えはない?
直接実行した時は__name__
に"main"が入り、
importしたときはhoge
などのファイル名が入っています。
この動作を確認するために下記のようなファイルを作ってみます。
def tasu(a, b):
print("method call" + __name__)
return a + b
if __name__=='__main__':
print(__name__)
print("4 + 6 = " + str(tasu(4, 6)))
python tasu.py
__main__
method call__main__
4 + 6 = 10
このように直接実行すると、__name__
には__main__
が入っています。
次にipythonで実行してみます。
In [1]: import tasu
In [2]: tasu.tasu(5, 8)
method calltasu
Out[2]: 13
importするだけだとif __name__ == "__main__"
ブロックが実行されません。
さらに関数を呼び出してメソッド内で__name__
をprintするとtasu
とファイル名が表示されます。
まとめ
- import hogeはhoge.pyファイルを実行しているだけ。
- importしたときに探すディレクトリの場所は
sys.path
で確認でき、変更が可能。 -
if __name__ == '__main__':
は直接ファイルを実行したときに実行され、デモやテストを書いておける。
こんな感じです。
実際にファイルに書いて実行したりipython上で__name__
と打ってみると理解が進むと思います。