
このレクチャーでは、Pythonでモジュールを作り、それをimportして使う方法を段階的に学びます。前章で作った「1ファイル版 Fortune Cookie」を出発点に、次のことを体験します。
- 言語ごとのメッセージを別ファイルに分ける
fortune.pyからモジュールを読み込む- モジュール化によってコードの見通しが良くなることを体感する
Table of Contents(目次)
モジュールとパッケージの準備
Pythonでは、関連するモジュールをまとめるフォルダをパッケージと呼びます。パッケージを作るときは、空の__init__.pyファイルを用意します。
__init__.pyの役割:
- フォルダをパッケージとしてPythonに認識させるために必要
- 空のままでもOK。後でパッケージ全体で共通の初期化処理を書くことも可能
- これがないと、Pythonはフォルダを単なるディレクトリとして扱い、
importできません
ディレクトリ構造のイメージ
fortune_cookie/
├─ fortune.py
└─ message/
├─ __init__.py
├─ language_en.py
└─ language_jp.py

ポイント:
- fortune_cookie/… プロジェクトのルート
- fortune.py… 実行用ファイル
- message/… メッセージ関連のモジュールをまとめたパッケージ
- __init__.py… パッケージを認識させるためのファイル
- language_en.py… 英語メッセージを格納するモジュール
- language_jp.py… 日本語メッセージを格納するモジュール
各言語のモジュールを作る
英語モジュール
# message/language_en.py
# MESSAGES はアプリ内で使う文言をdictでまとめたもの:
MESSAGES = {
'app_title': 'Fortune Cookie', # アプリのタイトル表示に使う文字列
'prompt_open': 'Would you like to open a cookie? (y/n): ', # ユーザーに操作を促すプロンプト
'fortune_prefix': 'Your fortune for today is:', # 運勢表示の前につける接頭文
'goodbye': 'See you tomorrow with more luck!' # プログラム終了時の挨拶
}
# FORTUNES はランダムに表示する運勢のlist
FORTUNES = [
'Great Fortune! A wonderful day awaits you.',
'Fair Fortune. Keep steady progress.',
'Little Fortune. Stay patient and try again.',
'Bad Fortune... but tomorrow is another chance.'
]
ポイント:
- 英語に関するデータだけを置くことで、後から修正や追加が簡単になります。
fortune.pyは処理専用、language_en.pyはデータ専用と役割を分けるイメージです。 - 英語の文言は翻訳担当者が編集するファイルと考え、ロジック(処理)は書かないようにします。データ(文言)を切り出しておくと、テキスト修正が発生してもプログラマのコードに手を入れずに済みます。
日本語モジュール
英語モジュールと同様に、日本語の文言を管理するファイルを作ります。
# message/language_jp.py
# MESSAGES はアプリ内で使う文言をdictでまとめたもの
MESSAGES = {
'app_title': 'フォーチュンクッキー', # アプリのタイトル表示に使う文字列
'prompt_open': 'クッキーを開きますか? (y/n): ', # ユーザーに操作を促すプロンプト
'fortune_prefix': 'あなたの今日の運勢は:', # 運勢表示の前につける接頭文
'goodbye': 'また明日も幸運を!', # プログラム終了時の挨拶
}
# FORTUNES はランダムに表示する運勢のlist
FORTUNES = [
'大吉!最高の一日になりそうです!',
'中吉。ちょっとした幸運が訪れるでしょう。',
'小吉。小さな努力が実を結びます。',
'凶...でも心配しすぎないでください。'
]
importの基礎と様々な記述方法
fortune.pyから、language_en.py, language_jp.pyのデータを読み込ませるには、importというキーワードを使います。フォルダ階層がある場合は、プロジェクトのルートディレクトリから見た階層をドット.でつないで指定します。今回の場合、ルートはfortune_cookie/です。
importには他のキーワードと組み合わせた書き方が複数あるので、まずはどのような指定方法があるのかを見ていきましょう。
階層:
ルートディレクトリ (fortune_cookie/)
└─ message/ (パッケージ)
├─ language_en.py (モジュール)
└─ language_jp.py (モジュール)
import モジュール名
fortune.pyの最終行のmain()が実行されないようにコメントアウトし、次のコードを実行してみましょう。
import message.language_en
import message.language_jp
print(message.language_en.MESSAGES)
print(message.language_en.FORTUNES)
print(message.language_jp.MESSAGES)
print(message.language_jp.FORTUNES)
上記コードのimport文は、各モジュール全体を読み込みます。モジュール名は、拡張子.pyを除いたPythonのファイル名です。変数や関数を呼び出すときはモジュール名.変数名のように書く必要があります。
(以下、language_enの読み込み例のみ示します。)
import モジュール名 as 別名
import message.language_en as lang
print(lang.MESSAGES)
print(lang.FORTUNES)
長い名前を短くして、コードを読みやすくできます。上記の場合、『message.language_enをlangという別名でimportする』という宣言になります。lang.MESSAGESやlang.FORTUNESのように記述することで、変数を参照することができます。
さらに、as構文を使用することで、条件によって読み込まれるモジュールが変更される場合でも、同じ名前で後続の処理を実行できます。次のコードの場合、言語(変数lang_code)が'en'と'jp'のどちらの場合であっても、後続の処理はlang.~で実行させることができます。
lang_code = 'en'
if lang_code == 'en':
import message.language_en as lang
elif lang_code == 'jp':
import message.language_jp as lang
print(lang.MESSAGES)
print(lang.FORTUNES)
from モジュール名 import [変数/関数/クラス]
from message.language_en import MESSAGES
print(MESSAGES)
必要な変数や関数だけを直接呼び出せます。長いモジュール名を省略できます。
上記の場合、『message.language_enから変数MESSAGESをimportする』という宣言になります。MESSAGESのみ読み込んでいるので、上記の書き方だと変数FORTUNESを参照することはできません。複数の変数や関数を参照したい場合は、次のコードのように読み込みたい対象をカンマで区切って定義します。
from message.language_en import MESSAGES, FORTUNES
print(MESSAGES)
print(FORTUNES)
from モジュール名 import [変数/関数/クラス] as 別名
from message.language_en import MESSAGES as en_messages
print(en_messages)
名前が重複する場合や、より明示的に書きたい場合に使います。上記の場合、『message.language_enから変数MESSAGESをen_messagesという別名でimportする』という宣言になります。
1つのモジュールから複数の変数・関数を、それぞれにasを使って別名を付けて読み込む時は、次のように複数行に分けて記述することになります。
from message.language_en import MESSAGES as en_messages
from message.language_en import FORTUNES as en_fortunes
print(en_messages)
print(en_fortunes)
fortune.py を修正してモジュールを使う
データをモジュールにまとめることでfortune.pyは処理専用になります。今後は、新しい言語モジュールが追加されたとしてもfortune.pyはほとんど触らずに済みます。
# fortune.py
import random
def main():
# 言語を選択
lang_code = input('言語を選んでください (jp/en): ')
# 言語コードに応じて読み込むモジュールを切り替える
if lang_code == 'en':
import message.language_en as lang
else: # 'jp' or else
import message.language_jp as lang
# クッキーを開きますか?
print(f"=== {lang.MESSAGES['app_title']} ===")
answer = input(lang.MESSAGES['prompt_open'])
if answer == 'y':
print(f"{lang.MESSAGES['fortune_prefix']} {random.choice(lang.FORTUNES)}")
else:
print(lang.MESSAGES['goodbye'])
main()
言語の管理をモジュールとして分けたことで、fortune.pyの見通しが良くなりました。モジュールのimportは、原則として、モジュールの先頭に記述していくのが基本です。しかし、条件によって異なるモジュールを読み込みたい時は、10~13行目のifブロックのように記述することもできます。条件分岐内のimport(遅延インポート)は、必要なモジュールのみを読み込むため、メモリ効率が良く、拡張もしやすい方法です。
モジュールは、as langとして読み込んでいるので、変数lang_codeの値が'en'であろうと'jp'であろうと、その後の処理はlang.MESSAGESもしくはlang.FORTUNESでデータを参照することができます。
まとめ:モジュール化のメリット
- ファイルが分かれることで見通しが良くなる
- データを別モジュールにすることで保守が容易になる
- 翻訳の修正作業や、他言語対応(フランス語・ドイツ語など)の追加が簡単になる
fortune.pyは言語管理以外の処理に集中できるようになる- ただし、現段階では、言語が増えた場合に
fortune.pyのifの条件式を増やすなどの作業は必要になります
- ただし、現段階では、言語が増えた場合に






