【Python】別ファイルでコードを分割してimportする方法をわかりやすく解説
はじめに
Pythonでコードを書いていると、最初は1つのファイルにすべての処理を書きたくなるかもしれません。
しかし規模が大きくなるにつれ、1つのファイルにまとめてしまうと管理や修正が難しくなることがあります。
そこで重要になるのが別ファイルでコードを分割して、それらをimport文で呼び出す方法です。
ファイルを分割することで、処理の見通しが良くなり、機能ごとに整理しやすくなります。
本記事では、Pythonにおける別ファイルへのimportを中心に、初心者の皆さんが理解しやすい形で解説します。
コード例や実務における利用イメージも交えながら、ぜひ学んでみてください。
この記事を読むとわかること
- 別ファイルをPythonでimportする基本的な仕組み
- よく使われるimportの書き方と実務での活用シーン
- 相対importと絶対importの違い
- import時につまずきやすいポイントと対処法
別ファイルをimportするメリットとは
別ファイルでコードを分割してimportすることで、いくつかの利点が得られます。
特に、開発の効率化やコードの見通しの良さは大きなポイントです。
コードの見通しが良くなる
規模の大きいプロジェクトになると、1つのファイルに書かれたコードの行数が膨大になります。
どこに何が書かれているかすぐに見つからない状態では、修正や機能追加に時間がかかってしまいます。
ファイルごとに処理を分割しておけば、「このファイルにはデータベース関連の処理」「あのファイルにはユーザー認証の処理」といった形で、役割ごとにまとまったコードを管理できます。
結果的に、トラブルが起きても原因箇所を特定しやすくなり、保守性が向上します。
再利用性が高まる
同じ処理を何度も書くのは手間がかかりますし、微妙に書き方が違っていると後で整合性を取るのが大変です。
共通機能を別ファイルにまとめておけば、必要な場所でimportするだけなので、DRY(Don't Repeat Yourself)原則にかなったコードを書きやすくなります。
チーム開発がしやすくなる
複数のプログラマで同時に作業するとき、1つのファイルを同時に編集すると競合が起きやすくなります。
ファイルが機能ごとに分割されていれば、編集箇所も自然に分かれやすくなるので、衝突や混乱が少なくなるでしょう。
Pythonにおける基本的なimportの仕組み
Pythonは、ファイルごとにモジュール(module)という単位でコードを管理します。
別ファイルに書かれた変数や関数を使う場合は、import
文でそのモジュールを読み込みます。
モジュールとは何か
モジュールとは、Pythonのファイル1つ分と考えてもらうとわかりやすいです。
ファイル名が sub.py
であれば、モジュール名も sub
となります。
実際にコードを書くときは、以下のように書きます。
# main.py import sub # sub.pyで定義した関数greetを呼び出す sub.greet()
このように、同じフォルダ(ディレクトリ)にある sub.py
を import sub
で読み込み、そこに定義されている関数 greet()
を呼び出しています。
たとえば、別ファイルである sub.py
に次のような処理が書かれているとします。
# sub.py def greet(): print("こんにちは!")
こうすると、main.py
から sub.greet()
を実行するだけで print("こんにちは!")
が呼び出されるわけです。
これが、Pythonにおける基本的なモジュールの考え方になります。
from import 構文
モジュール名を頻繁に書くのが面倒な場合は、from import 構文が便利です。
先ほどの例をもう一度少しだけ変えてみましょう。
# main.py from sub import greet # これで直接greet()を呼び出せる greet()
モジュール名を指定せずに、関数やクラスをそのまま利用できます。
長いモジュール名やクラス名を繰り返し書かなくて済むので、コードが読みやすくなるケースも多いでしょう。
一方で、どの関数やクラスがどのモジュールから来たのか一目でわからなくなりがちな面もあります。
バランスを見て、チーム内のルールやプロジェクト規模に応じて使い分けるのがおすすめです。
as を使った別名の付与
同じような名前がかぶりそうなときや、さらに略称で呼びたいときは as
を使います。
import sub as sb sb.greet()
または以下のように書くこともできます。
from sub import greet as hello hello()
こうすると、コードがコンパクトになります。
名前が衝突するのを避けたいときにも有用です。
実務での活用シーン
Pythonを業務で活用する場合、ファイルを分割し、モジュールとしてimportする方法が役立つ場面はいろいろあります。
データ解析や数値計算プロジェクトでの利用
データを加工する機能を1つのファイルにまとめ、グラフ描画や可視化などは別ファイルにまとめる、といった形です。
それぞれをimportすることで、処理を明確に分離できます。
データ処理は頻繁に変わりやすい部分なので、ファイルを独立させておくと保守もスムーズです。
Webアプリケーションの構築
Webフレームワークを使う際には、ビュー・モデル・コントローラーなどの役割に合わせてファイルを分割することが一般的です。
たとえば、「ユーザー管理」をする部分は user.py
、「投稿管理」をする部分は post.py
といったように機能単位で分割し、メインとなる app.py
などで必要な機能をimportします。
テストコードの分離
大規模開発になるとテストコードが膨大になります。
テスト用のファイルを別途作成しておけば、実装部分とは独立して保守できます。
また、CIツールなどからテストファイルをimport、あるいはテストフレームワークを通して実行するケースも多いです。
相対importと絶対importの違い
フォルダ構成が複雑になってくると、相対import と 絶対import を使い分ける必要が出てきます。
絶対import
絶対importとは、ルートとなるディレクトリからのパスを明示的に書いてimportする方法です。
たとえば、次のようなディレクトリ構成を考えてみてください。
my_project/ main.py utils/ math_ops.py string_ops.py
もし math_ops.py
から string_ops.py
の処理を呼び出したい場合、絶対importでは
import utils.string_ops
のようにディレクトリ構造から明示的に指定します。
ディレクトリが深くなるほどパス指定は長くなりますが、どこに何があるかがはっきりわかるのがメリットです。
相対import
一方の相対importは、現在のファイルに対して相対的に import パスを指定します。
同じディレクトリにあるモジュールなら .
(ドット1つ)を、1つ上のディレクトリにあるモジュールなら ..
(ドット2つ)を使ってパスを示します。
# math_ops.py から string_ops.py を相対パスでimportする場合 from . import string_ops
あるいは、さらに1つ上の階層にあるファイルを呼び出すなら、
from .. import main
のように書くこともできます。
相対importはプロジェクトの配置場所が変わったときに対応しやすいという面もありますが、ファイルの位置関係が見えにくいと混乱しやすい場合もあります。
ディレクトリ構成の例と実装
ここでは、もう少し複雑な構成例をご紹介します。
具体的なフォルダ構成とコード例を見ながら、どのようにimportを使うのかを確認してみてください。
my_project/ ┣ main.py ┗ app/ ┣ __init__.py ┣ config.py ┗ modules/ ┣ __init__.py ┣ data_handler.py ┗ display.py
上記のように、app
ディレクトリ配下に modules
というディレクトリを置き、そこに data_handler.py
と display.py
があるとします。
それぞれのファイルで役割を分けましょう。
data_handler.py
# data_handler.py def get_data(): return ["Apple", "Banana", "Cherry"] def filter_data(data_list): return [item for item in data_list if len(item) > 5]
display.py
# display.py def show_data(data_list): for item in data_list: print(item)
config.py
# config.py APP_NAME = "SampleApp" VERSION = "1.0"
main.py
# main.py from app.modules.data_handler import get_data, filter_data from app.modules.display import show_data import app.config as config def main(): print(config.APP_NAME) data = get_data() filtered = filter_data(data) show_data(filtered) if __name__ == "__main__": main()
このようにディレクトリを分割しておくと、役割がはっきりします。
main.py
でいろいろなファイルをimportしてまとめて実行する構成は、実務でもよく見かけるスタイルの1つです。
もし import エラーが出る場合は、Pythonの実行時にモジュールパスが適切に設定されていない可能性があります。
カレントディレクトリに気をつけて起動してみたり、IDEの設定を確認してみると良いでしょう。
import時につまずきやすいポイント
パスが通っていない
カレントディレクトリの設定やパスが原因で、思わぬ場所からスクリプトを実行してしまい、モジュールが見つからないエラーに陥るケースがあります。
コマンドラインで実行する場合は、できるだけ main.py
のある場所を起点として実行するのがわかりやすいです。
IDEやエディタを使っている場合は、実行設定の「Working Directory(作業ディレクトリ)」を正しく指定しておくとエラーを回避しやすくなります。
名前の衝突
複数のファイルで同じ名前の変数や関数を定義していると、importの際に名前がぶつかることがあります。
同じ機能の関数である場合は、共通モジュールに集約して名前を整理するなどの方針が考えられます。
どうしても衝突を避けられない場合は、as
を使って別名をつけるのもひとつの方法です。
ファイル名の衝突
Pythonのファイル名が、標準ライブラリと同じ名前になっていると意図せず衝突することがあります。
たとえば、random.py
というファイルを自作していると、標準ライブラリの random
と区別がつかなくなる可能性があります。
同名のファイルがないかどうか注意しましょう。
標準ライブラリと同じファイル名をつけると、Pythonのシステムが混乱して思わぬエラーの原因になることがあります。
ライブラリ名とかぶるファイル名は避けるようにしましょう。
importを使いこなすためのコツ
機能ごとにフォルダを分ける
同じ機能同士のファイルをまとめると、視覚的に整理しやすくなります。
フォルダ構成が明確だと、importパスもわかりやすくなり、チーム開発でも理解しやすい構造になるでしょう。
名前が重複しないように意識する
ファイル名やモジュール名は、機能を連想しやすい名称にすると同時に、標準ライブラリと重ならないように注意しましょう。
同様に、プロジェクト内で共通機能を持つファイル名も、名称が衝突しないようルールを決めておくと安心です。
importを使いすぎない
importをしすぎると、どこにどの機能があるのか把握しにくくなることがあります。
特に、from ... import *
で一括importしてしまうと、名前空間がごちゃ混ぜになるため注意が必要です。
使う必要のあるものだけを厳選してimportするのが基本です。
まとめ
Pythonでコードを分割して管理する際には、別ファイルへのimportが欠かせません。
機能ごとにファイルを整理すれば保守性が高まり、開発や改修がしやすい環境を作れます。
本記事では、
- 別ファイルをimportするメリット
- importの基本的な書き方
- 相対importと絶対import
- 実務での活用シーン
- トラブルシューティング
などについてお話ししました。
コード量が増えるほど、一つのファイルに詰め込むのは辛くなりますので、適度に分割し、importを使いこなしてみてください。
その際、ディレクトリ構造やファイル名の付け方もポイントになってきます。
自分のプロジェクトに合わせて柔軟に構成を考え、また実行時のパス設定や名前の衝突を避けるように注意しながら、より快適な開発環境を目指してみてはいかがでしょうか。