概要
自分でPythonのファイルを分割する場合に、
いつも悩むので、一度しっかりまとめようと思ったので、まとめました。
同じ悩みの人のお役に立てれば幸いです。
※以降の説明はすべて、main.pyが実際に実行するPythonファイルとなります。
インポートの基礎知識
Pythonのライブラリは主に以下の3種類となります。
- 標準ライブラリディレクトリ
- site-packagesディレクトリ(pip installでインストール)
- ユーザ別site-packagesディレクトリ(pip install --userでインストール)
Pythonが読み込むライブラリの場所を知りたい場合は、下記の様に実行すれば分かります。
user$ python
Python 3.6.8 (default, Mar 10 2019, 22:43:46)
[GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.10.44.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
なお、独自のインポートパスを追加したい場合は、以下のようにすれば追加できます。
(※<>の記号は不要です)
export PYTHONPATH="<追加したいパス>:$PYTHONPATH"
STEP1: .pyファイルのインポート(同階層)
一番基礎的なパターンです。
同じ階層に存在する、.pyファイル内の関数やクラスをインポートするパターンです。
.
├── lib_a.py
└── main.py
from lib_a import Student, add
taro = Student('taro', 25)
print(taro.age)
print(add(3, 8))
class Student:
def __init__(self, name: str, age: int):
self.__name: str = name
self.__age: int = age
@property
def name(self) -> str:
return self.__name
@property
def age(self) -> int:
return self.__age
@name.setter
def name(self, name: str) -> None:
self.__name = name
@age.setter
def age(self, age: int) -> None:
self.__age = age
def add(x: float, y: float) -> float:
return x + y
# 正常にインポートできている
$ python main.py
25
11
STEP2: .pyファイルのインポート(別階層)
同階層以外の場所のPythonファイルをインポートする場合は、環境変数PYTHONPATHにインポート対象のパスを追加する必要があります。
.
└── main.py
~/Downloads
└── lib_a.py
main.pyとlib_a.pyはSTEP1と同じものを利用します
# 正常にインポートできている
$ export PYTHONPATH="/Users/username/Downloads:$PYTHONPATH"
$ python main.py
25
11
STEP3: 1階層のパッケージをインポートする
Pythonにはモジュールとパッケージという概念があります。
ざっくり説明しますと、モジュールは単一のpythonファイル(.py)で、パッケージはモジュールが複数含まれているフォルダ、という理解でいいかと思います。
今回は1階層のパッケージ内のモジュールをインポートする方法を見てみます。
.
├── lib
│ └── lib_a.py
└── main.py
lib_aは同じものを使用します。
libパッケージ内のlib_aモジュールをインポートします。
from lib.lib_a import Student, add
taro = Student('taro', 25)
print(taro.age)
print(add(3, 8))
# 正常にインポートできている
$ python main.py
25
11
Pythonのインポート方法に関して
Pythonにおけるインポートの方法は2種類存在します。
- from ... import ... 方式
- import ... 方式
上記はfrom ... import ... 方式ですが、下記のようにimport方式でも問題なくインポート可能です。
ですが、インポートしたクラスや関数を使うためには、クラス名の前にパッケージ名などを明記する必要があります。
import lib.lib_a
# クラスを使うためには、パッケージ名、モジュール名を付ける必要がある
taro = lib.lib_a.Student('taro', 25)
print(taro.age)
print(lib.lib_a.add(3, 8))
ここで、下記のようにしてもインポートできるのでは?、と思われた方がいらっしゃるかもしれません。
# libのみをインポート
import lib
taro = lib.lib_a.Student('taro', 25)
print(taro.age)
print(lib.lib_a.add(3, 8))
こちらの方法では、インポートは出来ません。
Pythonのインポートでは、 インポートしたパッケージ内のモジュールは自動的にインポートされないという制約があるためです。
今回の場合では、libパッケージのみをインポートしても、内部のlib_aモジュールは自動的にはインポートされない、ということになります。
libのみをインポートして、lib_aモジュールをインポートする方法も存在しますので、
そちらを紹介します。
Pythonのパッケージには__init__.pyというファイルが必要となります。
(Python3系では、必須ではありません)
Pythonのパッケージをインポートした場合、この__init__.pyというファイルがまず実行されます。
__init__.pyファイル内に、lib_aをインポートする、という記述を書けば、main.py内でlibパッケージをインポートするだけで、自動的にlib_aモジュールがインポートされるようになります。
.
├── lib
│ ├── __init__.py
│ └── lib_a.py
└── main.py
from . import lib_a
# libをインポートする際に、__init__.py内で、lib_aをインポートしている
import lib
taro = lib.lib_a.Student('taro', 25)
print(taro.age)
print(lib.lib_a.add(3, 8))
# 正常にインポートできている
$ python main.py
25
11
STEP4: 複数階層のパッケージをインポートする
パッケージ内に複数の内部パッケージを含むような場合を考えてみます。
.
├── lib
│ ├── liba
│ │ └── lib_a.py
│ └── libb
│ └── lib_b.py
└── main.py
from lib.liba.lib_a import Student, add
taro = Student('taro', 25)
print(taro.age)
print(add(3, 8))
# 追記
taro.print()
from lib.libb.lib_b import b_print
# 下記のように相対インポートでも可
# from ..libb.lib_b import b_print
class Student:
def __init__(self, name: str, age: int):
self.__name: str = name
self.__age: int = age
@property
def name(self) -> str:
return self.__name
@property
def age(self) -> int:
return self.__age
@name.setter
def name(self, name: str) -> None:
self.__name = name
@age.setter
def age(self, age: int) -> None:
self.__age = age
def print(self) -> None:
b_print()
def add(x: float, y: float) -> float:
return x + y
def b_print():
print('module b execute print')
上記のフォルダ構成を見てください。
main.pyからlibaパッケージ内lib_aモジュールのStudentクラスのprint関数を呼び出します。
このprint関数は、libbパッケージ内lib_bモジュールのb_print関数を呼ぶ、という流れとなっています。
Pythonでは実行対象のPythonファイルの同階層以外のモジュールを呼び出すことが出来ないという制約があります。
例えば、main.pyの一つ上のディレクトリの.pyファイルをインポートすることは出来ません。
(もちろん、PYTHONPATHで追加すれば、インポートは可能です)
ですが、パッケージ内に限り、この制約を逃れることが可能です。
つまり、lib_aモジュールの上の階層に存在するlibbパッケージ内のlib_bモジュールをインポート(絶対インポート・相対インポート)することが可能です。
(もちろん、PYTHONPATHなどは使いません)
パッケージ最上位からすべて指定する方法が絶対インポートと呼ばれます。
今回はlibが最上位なので、「lib.libb.lib_b」となります。
from lib.libb.lib_b import b_print
代わりに、インポートしたいファイルを起点にして、指定する方法を相対インポートと呼びます。
lib_aから見ると、一つ上の階層にあるlibbを指定したいので、ドットを2つ繋げて、「..libb.lib_b」となります。
ドットが一つの場合は、同階層という意味になります。
from ..libb.lib_b import b_print
# 正常にインポートできている
$ python main.py
25
11
module b execute print
最後に
本記事の内容で自分でパッケージを作成・インポートする場合の基礎は理解できるのではないかと思います。
その他のパターンももしありましたら、教えていただければと思います。
ちなみに、アスタリスクでインポートする場合は、別の注意点が必要のようですので、下記記事を参照ください。
本記事が少しでも皆さんの助けになれば幸いです。