10分で分かるPythonのimport

## 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を実行しているだけ**です。

* #以下は解説コメントなので実際には表示されません。*

``` ipython
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__`で絶対パスが分かります。

``` ipython
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とするとカメさんが元気よく歩き出します。
<img width="714" alt="Screenshot 2018-04-07 09.22.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/107119/aeb7323a-b906-569c-3c19-07665f17d872.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)))
```

``` txt:実行結果
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__``と打ってみると理解が進むと思います。