当サイトは、アフィリエイト広告を利用しています

【Python】importとfrom~importの使い方

作成日:2024月04月22日
更新日:2024年04月22日

Pythonのモジュールやモジュールの中の関数等に対しての
importやfrom~importの使い方について調べたので忘備録として残す。

Pythonにおけるモジュール、パッケージについては下記記事でまとめています

importとは?

Pythonではあるモジュールで別のモジュールの関数や変数を
使いたい時に使用する

importではモジュールがまるごとimportされる

importの構文か下記のようになる

import構文
import パッケージ.モジュール

モジュールまでのパスを指定する

下記のような構成のプログラムで試してみる

bash
.
├── main.py
└── app
   ├── __init__.py
   ├── func1.py
   └── func2.py

importを使う

main.pyでapp/func1.pyの関数をimportして使ってみる

app/func1.py

app/func1.py
# 変数を設定
name = "test"
# 関数を設定
def hello():
print(name)

変数を表示する関数を定義しておく

app/func2.py

app/func2.py
# 変数を設定
name = "test2"
# 関数を設定
def hello2():
print(name)

同じことをするが別名の関数を持つfunc2.pyも用意しておく

main.py

main.py
# モジュール読み込み
import app.func1
# モジュールの関数を実行
app.func1.hello()
# 実行結果
# test
  • app.func1をapp.func1という名前でimport
  • appディレクトリのfunc1関数をimportして使っている

別名をつける

いちいちパスを書くのは面倒な場合は、別名をつけることができる

main.py
# モジュール読み込み(別名)
import app.func1 as func1
# モジュールの関数を実行
func1.hello()
# 実行結果
# test

複数import

複数importする場合は下記のように書ける

main.py
# モジュール読み込み
import app.func1 as func1
import app.func2 as func2
# モジュールの関数を実行
func1.hello()
func2.hello2()
# 実行結果
# test
# test2

from~importとは?

from~importとはただのimportがモジュールごとimportしているのに
対して、識別子(モジュールで定義され関数や変数、クラスなど)を指定してimportできる。
※importと同様にモジュールをimportすることもできる

色々とできるのでパターン別に書いて整理する

モジュールをfrom~import

通常のimportと同じ結果になる

main.py
# from パッケージ import モジュール
from app import func1
# モジュールの関数を実行
func1.hello()
# 実行結果
# test

基本的にモジュールをまるごとimportしたい場合は
from~importではなくimportを使う

指定した識別子をfrom~import

識別子を指定してのimportはfrom~importの方でしかできないので
こちらを使う

main.py
# from パッケージ.モジュール import 識別子
from app.func1 import hello,name
# モジュールの関数を実行
hello()
# モジュールの変数を表示
print(name)
# 実行結果
# test
# test

カンマ区切り複数指定もできる

非推奨パターン

可能ではあるがやらないほうがいいパターンも
まとめておく。

モジュールの識別子を全てをfrom~import

main.py
# from パッケージ.モジュール import 識別子(全て)
from app.func1 import *
# モジュールの関数を実行
hello()
# モジュールの変数を表示
print(name)
# 実行結果
# test
# test

この形はできるけど、非推奨となっている
モジュール内のすべての公開されている関数やクラスを現在の名前空間にインポートされるため
同じ名前の他の関数やクラスと名前が衝突する可能性あり、またコード可読性が下がるため。

必要な識別子を明示的にimportするようにする

パッケージ内のモジュールを全てfrom~import

パッケージ内のモジュールをまるごとまとめてimportする方法。
__init__.pyを作り、対象となるモジュールを配列で指定しておく必要がある

app/__init__.py
__all__ = ["func1","func2"]

main.pyで読み込み

main.py
# パッケージ内のモジュールを全て読み込み
from app import *
# モジュールの関数を実行
func1.hello()
func2.hello2()
# 実行結果
# test
# test2

非推奨の理由は「モジュールの識別子を全てをfrom~import」と同じ

絶対パスimportと想定パスimport

importでパスを指定するが、そのパスの指定方法には

  • 絶対パス指定
  • 相対パス指定

の2種類がある。

ちなみに上記のimportとfrom~importでは絶対パス指定を使っている

上記と同じ構成のプログラムで試してみる

bash
.
├── main.py
└── app
   ├── __init__.py
   ├── func1.py
   └── func2.py

ただfunc1.pyを少し書き換える

func1.py
from app.func2 import hello2
# 変数を設定
name = "test"
# 関数を設定
def hello():
print(name)
hello2()

func1でfunc2のhello2関数をimportして使うように変更する

絶対パスimport

絶対パス指定とはモジュールの完全なパスを指定してインポートする。
プロジェクトのルートディレクトリからのパスを指定する方法

func1.py
from app.func2 import hello2
# 変数を設定
name = "test"
# 関数を設定
def hello():
print(name)
hello2()

main.pyから実行

この状態でmain.pyを実行してみる

main.py
# モジュール読み込み
from app import *
# モジュールの関数を実行
func1.hello()
func2.hello2()
# 実行結果
# test
# test2
# test2

問題なく実行できる

app/func1を直接実行すると

app/func1を直接実行した場合は

error
ModuleNotFoundError: No module named 'app'

となりエラーになる。

通常,Pythonはモジュールを現在の作業ディレクトリから検索するので
func1.pyを直接実行した場合、作業ディレクトリはappになる

func1.pyの中でfrom app.func2 import hello2というインポート文を実行しようとすると、
Pythonはappディレクトリをさらに下の階層から検索しようとしてappディレクトリが見つからずエラーとなる。

通常、Pythonプロジェクトではモジュールが直接実行されることを想定していないため、
モジュールは他のスクリプト(main.py)からインポートして実行するようにする。

相対パスimport

相対パス指定はその名の通り、現在のモジュールの位置に基づいて相対的に
他のモジュールをインポートする。

.は現在のディレクトリを、..は親ディレクトリを表す

app/func1.py
from .func2 import hello2
# 変数を設定
name = "test"
# 関数を設定
def hello():
print(name)
hello2()
# 実行結果
# test
# test2
# test2

main.pyから実行

この状態でmain.pyを実行してみる

main.py
# モジュール読み込み
from app import *
# モジュールの関数を実行
func1.hello()
func2.hello2()
# 実行結果
# test
# test2
# test2

問題なく実行できる

app/func1.pyを直接実行

相対インポートは、パッケージ内のモジュール間でのみ機能する
したがって、func1.py を直接実行すると、Pythonはそれをパッケージの一部とは見なさないため、相対インポートし、エラーとなる。

要は直接実行時は相対インポートは機能しないのでエラーになる

どっちをつかえばいいか?

一般的な傾向としては、プロジェクトの構造が変更されたときにコードが壊れるリスクを減らすことができるため
や可読性の点から絶対パスの使用が推奨されている

しかし、複雑な構成であったり、小規模なプロジェクトやパッケージ内のモジュール間でのアクセスであれば
相対パスを使うのはありだと思う

参考

関連記事

新着記事

タグ別一覧
top