note.nkmk.me

Python, importの使い方(from, as, PEP8の推奨スタイル, 注意点など)

Date: 2018-07-22 / tags: Python

Pythonではimport文を使って標準ライブラリやpipでインストールしたパッケージ、自作のパッケージなどをインポートできる。

ここでは以下の内容について説明する。

  • モジュールとパッケージとライブラリ
  • importの基本的な使い方
  • PEP8で推奨されているimportの書き方
  • オブジェクト(関数や変数、クラス)を指定してインポート: from ... import ...
  • 別名をつけてインポート: import ... as ...
  • パッケージからモジュールやオブジェクトをインポート
  • 正しくインポートできない場合

importの対象となるディレクトリのパスを確認したり追加したりしたい場合は以下の記事を参照。

また、自作のライブラリをインポートする際に相対パスで上位ディレクトリ・サブディレクトリを指定したい場合は以下の記事を参照。

スポンサーリンク

モジュールとパッケージとライブラリ

Pythonでは関数やクラスなどをまとめて書いたファイルをモジュールという。

また、モジュールと__init__.pyを含むディレクトリをパッケージ(Regular packages)という。__init__.pyには初期化コードを記述するが、空のファイルでもOK。

Python3.3以降では、__init__.pyを含まないディレクトリもパッケージとしてインポートできるようになった。このようなパッケージを名前空間パッケージ(Namespace packages)という。

なお、Pythonには「ライブラリ」という用語はないが、パッケージやモジュールのことをライブラリと呼ぶ場合もある。厳格に定義されたものではない。

以降、importの基本的な使い方としてモジュールをインポートする方法を説明したあと、パッケージを扱う場合の注意点を述べる。

importの基本的な使い方

例として標準ライブラリのmathモジュールをインポートする。

以下のようにimport <モジュール名>とするとモジュールがmodule型のオブジェクトとしてインポートされる。print()で出力するとどのファイルを読み込んでいるかが確認できる。

import math

print(type(math))
# <class 'module'>

print(math)
# <module 'math' from '/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload/math.cpython-37m-darwin.so'>

<モジュール名>.<関数名><モジュール名>.<変数名>のようにモジュール内で定義された関数やグローバル変数などを使用できる。

print(math.radians(180))
# 3.141592653589793

print(type(math.radians))
# <class 'builtin_function_or_method'>

print(math.pi)
# 3.141592653589793

print(type(math.pi))
# <class 'float'>

なお、radians()は度をラジアンに変換する関数でpiは円周率が格納された変数。

モジュールの関数や変数を直接使えるようにインポートしたい場合は後述のfromを使う。import <モジュール名>.<関数名>などとするとエラーとなるので注意。

PEP8で推奨されているimportの書き方

Pythonのスタイルガイド(コーディング規約)であるPEP8ではimport文の書き方も記されている。

なお、あくまでもスタイルガイドなのでこのように書かないとエラーになるというわけではない。

複数モジュールのインポート

仕様ではimport文のあとに複数のモジュールをカンマで区切って書くことができるが、PEP8では推奨されていない。一行ずつ分けて書く。

# NG
import os, sys

# OK
import os
import sys

次に説明するようにfromを使ってオブジェクト(関数や変数、クラス)をインポートする場合はカンマで区切ってもOK。

from math import pi, radians

モジュールをインポートする順番

モジュールの種類によって以下の順番でグループ分けしてインポートするのが推奨されている。

  1. 標準ライブラリ
  2. サードパーティライブラリ
  3. ローカルライブラリ(自作のライブラリ)

グループ間は空白行で区切る。

PEP8には書かれていないが、グループ内の順番はアルファベット順に並べられることが多い。

import math
import os
import sys

import Requests

import my_package1
import my_package2

オブジェクト(関数や変数、クラス)を指定してインポート: from ... import ...

fromを使って、モジュールで定義されたオブジェクト(関数や変数、クラスなど)を指定してインポートすることができる。

単独のオブジェクト

from <モジュール名> import <オブジェクト名>でオブジェクトをインポートできる。

インポートしたオブジェクトは<オブジェクト名>で直接使用できる。インポートされるのは指定したオブジェクトのみでモジュール自体はインポートされない。他のオブジェクトを使用しようとするとエラーNameErrorになる。

from math import pi

print(pi)
# 3.141592653589793

# print(math.radians(180))
# NameError: name 'math' is not defined

複数のオブジェクト

同じモジュールから複数のオブジェクトをインポートする場合はカンマで区切る。

from math import pi, radians

print(pi)
# 3.141592653589793

print(radians(180))
# 3.141592653589793

多数のオブジェクトをインポートして一行が長くなってしまう場合は、括弧()を使えば改行して書ける。

from math import (
    e,
    exp
)

print(e)
# 2.718281828459045

print(exp(1))
# 2.718281828459045

ここでeは自然対数の底(ネイピア数)で、exp()は指数関数。以下の記事を参照。

すべてのオブジェクト

ワイルドカード*を使うとすべてのオブジェクトがインポートされる。

from math import *

print(pi)
# 3.141592653589793

print(cos(0))
# 1.0

print(sin(0))

cos(), sin()は三角関数。以下の記事を参照。

モジュール内で__all__が定義されていると、__all__に含まれるオブジェクトのみがインポートされる。

なお、*を使ったインポートはどの名前が名前空間に存在しているか不明瞭であるためPEP8では推奨されていない。

別名をつけてインポート: import ... as ...

asを使うとモジュールやオブジェクトに別名をつけてインポートできる。別名をつけた場合、元の名前は使えない。

モジュールに別名をつける例。

import math as m

print(m.pi)
# 3.141592653589793

# print(math.pi)
# NameError: name 'math' is not defined

オブジェクトに別名をつける例。

from math import pi as PI

print(PI)
# 3.141592653589793

# print(pi)
# NameError: name 'pi' is not defined

NumPyやpandasなど、省略名でインポートするのが慣例となっているライブラリもある。

import numpy as np
import pandas as pd

パッケージからモジュールやオブジェクトをインポート

パッケージからモジュールやオブジェクトをインポートする場合、その構成や__init__.pyの記述によってインポートの方法に注意が必要。

urllibの例

標準ライブラリのurllibを例として、パッケージからモジュールやオブジェクトをインポートする。

urllibディレクトリに以下のようにファイル(モジュール)が格納されている。__init__.pyは空。

urllib/
├── __init__.py
├── error.py
├── parse.py
├── request.py
├── response.py
└── robotparser.py

import urllibとした場合、配下のモジュールを使うことはできない。例えばurllib.errorとするとエラーAttributeErrorとなる。

import urllib

print(type(urllib))
# <class 'module'>

print(urllib)
# <module 'urllib' from '/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/__init__.py'>

# print(urllib.error)
# AttributeError: module 'urllib' has no attribute 'error'

<パッケージ名>.<モジュール名>でモジュールをインポートする必要がある。

import urllib.error

print(urllib.error)
# <module 'urllib.error' from '/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/error.py'>

print(urllib.error.HTTPError)
# <class 'urllib.error.HTTPError'>

from <パッケージ名> import <モジュール名>でもOK。

from urllib import error

print(error)
# <module 'urllib.error' from '/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/error.py'>

print(error.HTTPError)
# <class 'urllib.error.HTTPError'>

オブジェクトを指定してインポートすることも可能。

from urllib.error import HTTPError

print(HTTPError)
# <class 'urllib.error.HTTPError'>

このように、__init__.pyで特に初期化コードが記述されていない場合は、パッケージをインポートするのではなく配下のモジュールをインポートする必要があるので注意。

なお、IPython, Jupyter Notebookを使っている場合、urllibをインポートしただけでurllib.parseも使えるようになるが、これはIPythonの起動時の処理に起因する挙動。

collectionsの例

異なる例としてcollectionsを挙げる。

collectionsディレクトリは以下のような構成になっている。

collections/
├── __init__.py
└── abc.py

collectionsではurllibのように配下にモジュールのファイルが格納されているのではなく、__init__.pyでクラスなどが定義されている。CounterOrderedDictなどはモジュールではなくクラス。

このような場合、パッケージをインポートした上で<パッケージ名>.<クラス名>としてクラスを使用できる。

import collections

print(collections)
# <module 'collections' from '/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/collections/__init__.py'>

print(collections.Counter)
# <class 'collections.Counter'>

<パッケージ名>.<クラス名>としてクラスをインポートすることはできない。

# import collections.Counter
# ModuleNotFoundError: No module named 'collections.Counter'

fromを使ってクラスをインポートするのはOK。

from collections import Counter

print(Counter)
# <class 'collections.Counter'>

NumPyの例

サードパーティライブラリとしてNumPyを例とする。

NumPyではnumpyディレクトリの__init__.pyの中で各サブパッケージをインポートしている。

このため、それぞれのモジュールをインポートする必要はなく、import numpy as npとするだけで各種の関数などが使える。

scikit-learnの例

異なる例としてscikit-learnを挙げる。

scikit-learnではsklearnディレクトリの__init__.pyではサブパッケージをインポートしていない。

このため、サブパッケージを明示的にインポートする必要がある。

from sklearn import datasets, model_selection, svm, metrics

なお、基本的にはドキュメントにどのようにインポートすればいいか書いてあるので、__init__.pyを読む必要はない。

正しくインポートできない場合

インポート関係の主なエラーとして以下の2つがある。

ModuleNotFoundError

モジュールが見つからないというエラー。

ModuleNotFoundError: No module named 'xxx'

単純に名前が間違っているか、importの対象となるディレクトリのパスの指定が間違っている可能性がある。

あるいは、上のcollecrionsの例のように、モジュールではなくクラスなどをインポートしようとした場合にもModuleNotFoundErrorとなる。関数やクラスなどのオブジェクトをインポートする場合はfromを使う。

AttributeError

インポートしたモジュールに指定した属性がないというエラー。

AttributeError: module 'xxx' has no attribute 'yyy'

単純な名前間違いのほか、想定と異なるファイルがインポートされている可能性がある。

例えば、import <モジュール名>としたときに最優先でモジュールが探索されるのは実行スクリプトファイルと同一ディレクトリであるため、そこに<モジュール名>.pyというファイルがあるとそのファイルがモジュールとしてインポートされてしまう。

print(<モジュール名>)で想定の場所からインポートされているかを確認して、想定外のファイルがインポートされている場合は該当ファイルをリネームするなどして対処する。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事