importしたら何が起きているの?

分かったようで分からない。
使えるけどよく知らない。
そんなimportしたら何が起きるのかを調べてみました。

動作環境(バージョン)

ipython : 6.2.1
python: Python 3.6.4 :: Anaconda, Inc.

カレントディレクトリに下記のファイルを置いています。

hoge.py
def hoge():
    print("ほげメソッド!")

print("ほげぇ!")
fuga.py
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'

出力で出てきたファイルを開くとちゃんとpyhonで記述されていることが分かります。

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とするとカメさんが元気よく歩き出します。
Screenshot 2018-04-07 09.22.28.png
ただあくまでもデモ用なのでimport turtleのときは実行しないようにしています。
しかしいくらカメさんが可愛いとといってもimportのたびに動かれてはウンザリしてしまうでしょう。

このようにモジュールとして読み込むときには実行して欲しくないデモやテストなどの処理を書いておける書き方になります。

if __name__ == "__main__":の目的は分かったけどこの気持ち悪い書き方は何?

__name__などちょっと見慣れないものが入っていますが、ただのif文です。

"__main__"は見ての通り文字列なので入門書でよく見る
if student == "Ken":と同じです。

え?__name__なんて宣言した覚えはない?

直接実行した時は__name__に"main"が入り、
importしたときはhogeなどのファイル名が入っています。

この動作を確認するために下記のようなファイルを作ってみます。

tasu.py
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__と打ってみると理解が進むと思います。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.