当サイトは、アフィリエイト広告を利用しています
Pythonのモジュールやモジュールの中の関数等に対しての
importやfrom~importの使い方について調べたので忘備録として残す。
Pythonにおけるモジュール、パッケージについては下記記事でまとめています
Pythonではあるモジュールで別のモジュールの関数や変数を
使いたい時に使用する
importではモジュールがまるごとimportされる
importの構文か下記のようになる
import パッケージ.モジュール
モジュールまでのパスを指定する
下記のような構成のプログラムで試してみる
.├── main.py└── app├── __init__.py├── func1.py└── func2.py
main.pyでapp/func1.pyの関数をimportして使ってみる
# 変数を設定name = "test"# 関数を設定def hello():print(name)
変数を表示する関数を定義しておく
# 変数を設定name = "test2"# 関数を設定def hello2():print(name)
同じことをするが別名の関数を持つfunc2.pyも用意しておく
# モジュール読み込みimport app.func1# モジュールの関数を実行app.func1.hello()# 実行結果# test
いちいちパスを書くのは面倒な場合は、別名をつけることができる
# モジュール読み込み(別名)import app.func1 as func1# モジュールの関数を実行func1.hello()# 実行結果# test
複数importする場合は下記のように書ける
# モジュール読み込みimport app.func1 as func1import app.func2 as func2# モジュールの関数を実行func1.hello()func2.hello2()# 実行結果# test# test2
from~importとはただのimportがモジュールごとimportしているのに
対して、識別子(モジュールで定義され関数や変数、クラスなど)を指定してimportできる。
※importと同様にモジュールをimportすることもできる
色々とできるのでパターン別に書いて整理する
通常のimportと同じ結果になる
# from パッケージ import モジュールfrom app import func1# モジュールの関数を実行func1.hello()# 実行結果# test
基本的にモジュールをまるごとimportしたい場合は
from~importではなくimportを使う
識別子を指定してのimportはfrom~importの方でしかできないので
こちらを使う
# from パッケージ.モジュール import 識別子from app.func1 import hello,name# モジュールの関数を実行hello()# モジュールの変数を表示print(name)# 実行結果# test# test
カンマ区切り複数指定もできる
可能ではあるがやらないほうがいいパターンも
まとめておく。
# from パッケージ.モジュール import 識別子(全て)from app.func1 import *# モジュールの関数を実行hello()# モジュールの変数を表示print(name)# 実行結果# test# test
この形はできるけど、非推奨となっている
モジュール内のすべての公開されている関数やクラスを現在の名前空間にインポートされるため
同じ名前の他の関数やクラスと名前が衝突する可能性あり、またコード可読性が下がるため。
必要な識別子を明示的にimportするようにする
パッケージ内のモジュールをまるごとまとめてimportする方法。
__init__.pyを作り、対象となるモジュールを配列で指定しておく必要がある
__all__ = ["func1","func2"]
main.pyで読み込み
# パッケージ内のモジュールを全て読み込みfrom app import *# モジュールの関数を実行func1.hello()func2.hello2()# 実行結果# test# test2
非推奨の理由は「モジュールの識別子を全てをfrom~import」と同じ
importでパスを指定するが、そのパスの指定方法には
の2種類がある。
ちなみに上記のimportとfrom~importでは絶対パス指定を使っている
上記と同じ構成のプログラムで試してみる
.├── main.py└── app├── __init__.py├── func1.py└── func2.py
ただfunc1.pyを少し書き換える
from app.func2 import hello2# 変数を設定name = "test"# 関数を設定def hello():print(name)hello2()
func1でfunc2のhello2関数をimportして使うように変更する
絶対パス指定とはモジュールの完全なパスを指定してインポートする。
プロジェクトのルートディレクトリからのパスを指定する方法
from app.func2 import hello2# 変数を設定name = "test"# 関数を設定def hello():print(name)hello2()
この状態でmain.pyを実行してみる
# モジュール読み込みfrom app import *# モジュールの関数を実行func1.hello()func2.hello2()# 実行結果# test# test2# test2
問題なく実行できる
app/func1を直接実行した場合は
ModuleNotFoundError: No module named 'app'
となりエラーになる。
通常,Pythonはモジュールを現在の作業ディレクトリから検索するので
func1.pyを直接実行した場合、作業ディレクトリはappになる
func1.pyの中でfrom app.func2 import hello2というインポート文を実行しようとすると、
Pythonはappディレクトリをさらに下の階層から検索しようとしてappディレクトリが見つからずエラーとなる。
通常、Pythonプロジェクトではモジュールが直接実行されることを想定していないため、
モジュールは他のスクリプト(main.py)からインポートして実行するようにする。
相対パス指定はその名の通り、現在のモジュールの位置に基づいて相対的に
他のモジュールをインポートする。
.
は現在のディレクトリを、..
は親ディレクトリを表す
from .func2 import hello2# 変数を設定name = "test"# 関数を設定def hello():print(name)hello2()# 実行結果# test# test2# test2
この状態でmain.pyを実行してみる
# モジュール読み込みfrom app import *# モジュールの関数を実行func1.hello()func2.hello2()# 実行結果# test# test2# test2
問題なく実行できる
相対インポートは、パッケージ内のモジュール間でのみ機能する
したがって、func1.py
を直接実行すると、Pythonはそれをパッケージの一部とは見なさないため、相対インポートし、エラーとなる。
要は直接実行時は相対インポートは機能しないのでエラーになる
一般的な傾向としては、プロジェクトの構造が変更されたときにコードが壊れるリスクを減らすことができるため
や可読性の点から絶対パスの使用が推奨されている
しかし、複雑な構成であったり、小規模なプロジェクトやパッケージ内のモジュール間でのアクセスであれば
相対パスを使うのはありだと思う