あまり基礎から教えてもらうことがないpythonのimportについて。モジュール？パッケージ？クラス？

#はじめに
pythonの基礎として、importの書き方を記載します。

#環境
MacOS
anaconda1.8.7
python3.6

#こんなこと思ったことありませんか？

pythonを始めてまもない人が、いろんなコードをみて、「書き方が違う」みたいなことを思ったことありませんか？例えば

```python
import matplotlib.pyplot as plt
from matplotlib import pyplot as plt
```
なんで書き方違うのか？結局どれがどれでどうなってるのか？結局慣例的に記憶することになるからどうでもいいんだけど。となってることもあるんじゃないでしょうか。

#モジュールとかパッケージとかライブラリとかってなに？

-*関数*
def文。関数名()というようにして実行する。一番小さい単位。

-*モジュール*
複数の関数集めて一つのファイルに記述したもの。
※ファイル名から拡張子.pyを除いたものがモジュール名になる。

-*パッケージ*
`__init__.py`と複数のモジュール(.pyファイル)が**ディレクトリ**にまとまったもの。パッケージの中にパッケージを含めることもできます。ディレクトリ名がパッケージ名となり、`親.子.モジュール`のように.で区切って指定することができます。
`__init__.py`にはパッケージの初期化処理を記述します。なければ空でも問題ありません。
>Python3.3以降では、\_\_init\_\_.pyを含まないディレクトリもパッケージとしてインポートできるようになった。このようなパッケージを名前空間パッケージ（Namespace packages）という。



-*ライブラリ*
（どうやら）Pythonには「ライブラリ」という用語の定義はなく、関数・モジュール・パッケージの総称、一般的な意味合いとして使われているらしいです。または、いくつかのパッケージをまとめて一つのライブラリとしてインストールするようにしたものを指すこともあります。

#importやってみる

モジュールを使用するにはimportを使います。

-import モジュール名
-import モジュール名 as 略称


例えば以下でmathをimportして型を調べてみます。

```python
>>> import math
>>> print(type(math))
<class 'module'>
>>> print(math)
<module 'math' from '/Users/hoge/anaconda3/lib/python3.6/lib-dynload/math.cpython-36m-darwin.so'>
```
moduleですね。
ついでにどのファイルを読み込んでいるか見てみます。

```python
>>> print(math)
<module 'math' from '/Users/hoge/anaconda3/lib/python3.6/lib-dynload/math.cpython-36m-darwin.so'>
```

次に
-<モジュール名>.<関数名>
-<モジュール名>.<変数名>

のようにすることでモジュール内で定義された関数やグローバル変数などを使用できます。

```python
>>> print(math.radians(180))
3.141592653589793
>>> print(type(math.radians))
<class 'builtin_function_or_method'>
>>> print(math.e)
2.718281828459045
>>> print(type(math.e))
<class 'float'>
```
※math.eは自然対数の底（ネイピア数)です。

上の関数の呼び出しを行うたびに毎回入力するのは面倒なので
そんなときはfromを使ってimportを行います

-from モジュール名 import オブジェクト(クラス名もしくは関数名もしくは変数名）

```python
>>> from math import pi, e
>>> print(e)
2.718281828459045
>>> print(pi)
3.141592653589793
```

以下のようにワイルドカードを使うとすべてのオブジェクトをインポートすることができます。
※ただしPEP８ではこのimportは名前空間の存在が不明瞭になるので推奨はされていないです。

```python
from math import *
```

#パッケージからモジュールやオブジェクトをimport

以下のようにimport sklearnとしても、配下のモジュールを使うことはできません。AttributeErrorとなります。

```python
>>> import sklearn
>>> print(sklearn)
<module 'sklearn' from '/Users/hoge/anaconda3/lib/python3.6/site-packages/sklearn/__init__.py'>

>>> print(sklearn.tree)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'sklearn' has no attribute 'tree'
```
<パッケージ名>.<モジュール名>
でモジュールをインポートする必要があります。
sklearnパッケージの中にtreeパッケージがあって、その下にDecisionTreeClassifierクラスがあって、その中に関数がある。

```python
>>> import sklearn.tree #from sklearn import treeでもいい
>>> print(sklearn.tree)
<module 'sklearn.tree' from '/Users/hoge/anaconda3/lib/python3.6/site-packages/sklearn/tree/__init__.py'>

>>> print(sklearn.tree.DecisionTreeClassifier)
<class 'sklearn.tree.tree.DecisionTreeClassifier'>
```
オブジェクトを指定してimportする場合は

```python
from sklearn.tree import DecisionTreeClassifier
```
dir（）を使うことで、配下にあるものを確認することができます。

```python
>>> dir(sklearn.tree)
['DecisionTreeClassifier', 'DecisionTreeRegressor', 'ExtraTreeClassifier', 'ExtraTreeRegressor', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '_criterion', '_splitter', '_tree', '_utils', 'export', 'export_graphviz', 'tree']
```

#補足：モジュールの作成

.pyの拡張子をもつファイルは、pythonのモジュールとして他のモジュールから利用することができます。
以下に簡単なモジュールを作ってみます。

```python:testmodule.py
class Testclass:
    def testkansu(self, str):
        print(str)

if __name__ == '__main__':
    test = Testclass()
    test.testkansu("test_dayo")  
```

実行します。

```terminal
$ python testmodule.py
test_dayo
```
他のモジュールから、importで呼び出して、moduleからclass生成をします。
※拡張子の.pyは不要
※モジュールとしてimportで呼び出した場合は`__main__`以下は実行されません。

```python
>>> import testmodule
>>> a = testmodule.Testclass()
>>> a.testkansu("test-dayo")
test-dayo
```

fromを使ってオブジェクトを呼び出してみます

```python
>>> from testmodule import Testclass 
>>> a = Testclass()
>>> a.testkansu("test-dayo")
test-dayo

>>> dir(Testclass)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'testkansu']
```

#補足の補足

ファイル内にあった`__main__`とかの兄弟について。

```
パッケージ名(__package__)
__package__ は、現在のパッケージ名を示します。

ファイル名(__file__)
__file__ は、現在のファイル名を示します。

モジュール名(__name__)
__name__ は、現在のモジュール名を示します。
メインモジュールの場合は __main__ という名前が設定されます。

ビルトインモジュール(__builtin__)
__builtin__ は、open() などのビルトインオブジェクトを包含するモジュールを示します。
```


#importに関するエラー

```python
ModuleNotFoundError
``` 

モジュールが見つからない時のエラー。
名前が間違っているか、importの対象ディレクトリのパスの指定が間違ってい場合、またモジュールではなくオブジェクトなどをimportしようとした場合にもModuleNotFoundErrorとなります。オブジェクトをインポートする場合はfromを使います。

```
AttributeError
```

importしたモジュールに指定した属性がない時にでるエラー。
名前が
間違っているか、想定と異なるファイルがimportされている可能性がある。

#参考
[Pythonのimportについてまとめる](https://qiita.com/suzuki-hoge/items/f951d56290617df4279e)
[Macでtreeコマンド](https://qiita.com/kanuma1984/items/c158162adfeb6b217973)
[とほほのWWW入門](http://www.tohoho-web.com/www.htm)
[ざっくりん雑記](http://azuuun-memorandum.hatenablog.com/entry/2015/05/09/002549)

#おわり