サイトアイコン Python Snippets

ワイルドカードインポート(import *)は推奨されない

from hoge import *とすることで、hogeモジュールのすべてをインポートできますが、これは雑なインポートの指定方法で意図しない変数、関数までこのモジュールの名前空間にインポートしてしまうので推奨されない。

pythonの公式のスタイルガイドであるPEP8でも非推奨となっている。

http://pep8-ja.readthedocs.io/ja/latest/#import
ワイルドカードを使った import (from import *) は避けるべきです。なぜなら、どの名前が名前空間に存在しているかをわかりにくくし、コードの読み手や多くのツールを混乱させるからです。

ワイルドカードインポートによって混乱する例

あるモジュールmain.pyがfirst.pyに依存しfirst.pyはsecond.pyに依存するとする。

main --> first --> second

first.pyでは、second.pyのすべてをワイルドカードインポートした場合、secondモジュールのすべてのグローバル変数、関数がfirst.pyの名前空間に入る。

# second.py
var_x = 1
def func1():
    pass
# first.py
from second import *
var_y = 2
def func2():
    pass

first.pyからはsecond.pyのfunc1関数を使いたいだけだったが、var_xの変数もインポートされる。

同様にmain.pyはfirst.pyをワイルドカードインポートすると、first.pyの全変数、関数がインポートされる。これにはfirst.pyがインポートしていたsecond.pyの内容までもインポートされる。

# main.py
from first import *
var_z = 3
def func3():
    pass

print(dir())

dir関数で定義された名前を確認すると、func1, func2, func3, var_x, var_y, var_zすべてが参照可能になっている。

[ ...中略..., 'func1', 'func2', 'func3', 'var_x', 'var_y', 'var_z']

意図しないモジュールからのインポートも行われるため定義位置を把握するのがとても難しくなる。
(main.pyでvar_xが参照できるのは、first.pyを参照し、second.pyのインポートからたどることでやっとvar_xの存在がわかる)

これはシンプルな例だが、カジュアルにワイルドカードインポートを使うとこれが肥大化しソースコードの可読性が著しく悪くなる。

second.pyに関数を一つ追加すると、main.pyでも自動的に参照できるようになる点も危険。

インポートする順番によって意図せず上書きする可能性がある

func1という関数が定義されたhogeモジュール。

# hoge.py
def func1():
    print("func1 called")

main.pyでは、円周率πを使用したかったために、mathモジュールのpi定数をインポートしていた。
ここから、hogeモジュールの関数を使いたいために、hogeモジュールをワイルドカードインポートをした。

# main.py
from math import pi
from hoge import *

func1()
print(pi)

main.pyスクリプトの実行結果は、以下のようになり円周率πの値が出力される。

func1 called
3.141592653589793

この状態で、hoge.pyで何気なくpiというグローバル変数を定義すると、main.pyがインポートしたpi変数を上書きしてしまうことになる。

# hoge.py
def func1():
    print("func1 called")
pi = 12345
func1 called
12345

hoge.pyで記述した内容は、piというグローバル変数を作っただけであり、mathモジュールのpi定数を上書きしたわけではない。
しかしmain.pyではワイルドカードインポートしているため、main.pyの名前空間ではpi変数は、hogeモジュールのpi変数を参照することになる。

当初main.pyを記述したときには、hogeモジュールを確認しpi変数がなく上書きされなかったのかもしれない。だがあとからhogeモジュールだけを更新するだけでmainモジュールにも影響を与えてしまっている。

意図しないインポートをしないためには、main.pyからは from hoge import func1 という形で必要なものだけインポートするのがよい。

関連記事:

モバイルバージョンを終了