こんにちは、えびかずきです。
Pythonはその強力なライブラリとモジュールが豊富に揃っていることで知られていますが、それらを適切に活用するためにはimportの仕組みを理解することが重要です。この記事では、Pythonのimportの基本を解説していきます。
では説明していきます。
要点
sys.pathについて
•基本的に実行スクリプトの階層が追加される
•python -m でモジュールとして実行した場合は作業ディレクトリの階層が追加される
相対インポートについて
•相対インポートできるモジュールはsys.path
内のディレクトリパスより下の階層のモジュールに限る
import文の基本
Pythonのimport文は他のモジュールの機能を使えるようにする基本的な機能です。例えば、mathモジュールをimportして、その中の関数を利用することができます。
import math
print(math.sqrt(16)) # 4.0
このように、import モジュール名
とすることで指定したモジュール全体がimportされます。モジュール内の特定の関数やクラスだけを使いたい場合は、以下のようにfrom モジュール名 import 関数名
と記述します。
from math import sqrt
print(sqrt(16)) # 4.0
Pythonのimport文にはas
というキーワードを使った使い方もあります。これはモジュールをimportする際に別名をつけるためのものです。この機能は特に、モジュール名が長い場合や、同名の関数やクラスがある場合に有用です。
たとえば、以下のようにimport モジュール名 as 別名
と記述することで、モジュール名
を別名
で参照することができます。
import math as m
print(m.sqrt(16)) # 4.0
この例では、mathモジュールをmという名前でimportしています。これにより、モジュール名を短くすることができ、コードの可読性を向上させることができます。
importできるモジュールについて
importできるモジュールはsys.path
に記述されているディレクトリパス配下にあるものに限ります。ターミナルからpython main.py
のように直接スクリプトを実行した場合には、作業ディレクトリパスではなく、スクリプトが存在するディレクトリパスがsys.path
に追加されることを覚えておきましょう。
一方で、python -m module
のようにスクリプトをモジュールとして実行した場合にはターミナルの作業ディレクトリがsys.path
に追加されます。
Packageをimportしてはいけない
Pythonでは、パッケージを直接importすると、その配下のモジュールがimportできなくなることがあります。これはPythonがパッケージレベルのimportではなく、モジュールレベルのimportを期待しているためです。例えば、以下のようなディレクトリ構造があるとします。
mypackage/
__init__.py
mymodule.py
この時、import mypackage
とするとmypackage.mymodule
は使用できません。
import mypackage
mypackage.mymodule
# AttributeError: module 'mypackage' has no attribute 'mymodule'
しかし、パッケージの__init__.py
ファイルに配下のモジュールをimportする記述がある場合、この問題は解決します。__init__.py
はパッケージがimportされたときに実行される特別なファイルで、ここにモジュールのimport文を書くことで、パッケージをimportした時に自動的にモジュールもimportされます。
以下のように__init__.py
にimport .mymodule
を追加します。
# mypackage/__init__.py
import .mymodule
これで、import mypackage
とした時にmypackage.mymodule
も一緒にimportされます。
import mypackage
mypackage.mymodule # This is now possible
よって、パッケージをimportする際は、その配下のモジュールが正しくimportされるように、適切な設定が必要であるという注意点があります。
実際のライブラリでこの現象を確認してみましょう。
例えば、numpyはパッケージを直接importすることができます。
import numpy
print(numpy.random) # <module 'numpy.random' from '/usr/local/lib/python3.6/dist-packages/numpy/random/__init__.py'>
一方、scikit-learnではパッケージを直接importしてもその配下のモジュールはimportできません。
import sklearn
print(sklearn.linear_model) # AttributeError: module 'sklearn' has no attribute 'linear_model'
このように、パッケージをimportする際には、そのパッケージがモジュールを自動的にimportする設定になっているかどうかを確認する必要があります。
相対import
Pythonの相対importとは、同じパッケージに属するモジュールをインポートする方法です。.
や..
を使って現在のモジュールの位置から相対的にインポートするモジュールの位置を指定します2。
相対importの注意点は、トップレベルのスクリプトでは使えないことです3。トップレベルのスクリプトとは、直接実行されるスクリプトのことです。相対importは、パッケージ内のモジュールをインポートするときにのみ使えます3。ちなみに相対インポートできるモジュールはsys.path内のディレクトリパスより下の階層のモジュールに限ります。つまりパッケージ階層を超えたディレクトリのモジュール、例えばトップレベルのスクリプトと同階層のモジュールなどはインポート出来ません。
では相対importの例を見てみましょう。以下のようなディレクトリ構造があるとします。
my_package/
__init__.py
module_a.py
module_b.py
sub_package/
__init__.py
module_c.py
module_d.py
main.py
ここで、module_a.py
からmodule_b.py
をインポートするには、以下のように書けます。
# module_a.py
from . import module_b # .は現在のディレクトリを表す
また、module_c.py
からmodule_d.py
をインポートするには、以下のように書けます。
# module_c.py
from . import module_d # .は現在のディレクトリを表す
さらに、module_c.py
からmodule_a.py
をインポートするには、以下のように書けます。
# module_c.py
from .. import module_a # ..は上位のディレクトリを表す
しかし、main.py
からmodule_a.py
をインポートするには、相対importは使えません。main.py
はトップレベルのスクリプトなので、絶対importを使わなければなりません。以下のように書けます。
# main.py
import my_package.module_a # パッケージ名から始める
以上が、Pythonの相対importに関する説明です。相対importは、パッケージ内のモジュールをインポートするときに便利な方法ですが、トップレベルのスクリプトでは使えないことに注意しましょう。
まとめ
Pythonのimportまわりの基本について解説しました。私自身importまわりの仕組みがわからなくなって調べ直すことがよくあります。たぶん3ヶ月後ぐらいにはまた忘れちゃってると思うので、この備忘録で復習することになりそうです。
参考
コメントを書く