Python:モジュールとパッケージ
1学習の目的
- import で標準ライブラリを使い、既にある道具で問題を解けるようになる。自分で書かずに済むコードを見分けられるようになる。
- 自作の関数や設定値を別ファイルに切り出し、複数のファイルから使い回せるようになる。1ファイル1000行のコードから卒業できる。
2基礎解説
| やりたいこと | 書き方 | 呼び出し方 |
|---|---|---|
| モジュール全体を使う | import math | math.sqrt(16) |
| 一部だけ取り込む | from math import sqrt | sqrt(16) |
| 別名を付ける | import math as m | m.pi |
| 自作ファイルを使う | import utils | utils.with_tax(1000) |
- import math したら math.sqrt() のように「モジュール名.関数名」で呼ぶ。どこから来た関数か一目で分かるのが利点。
- from math import sqrt なら直接 sqrt() と書ける。ただし from math import * は何が入ってくるか分からず名前が衝突するので使わない。
- 自作モジュールは同じフォルダに .py を置いて import ファイル名。import utils と書き、.py は付けない。
- if __name__ == "__main__": の中身は直接実行したときだけ動き、importされたときは動かない。動作確認用コードの置き場所。
- パッケージ=モジュールを入れたフォルダ。中に __init__.py を置き、from mypkg import tax のように読み込む。
現場使用例:標準ライブラリ(math / statistics / os / csv / datetime / json)、社内の共通処理を utils.py に切り出す、設定値を config.py に分離して環境ごとに差し替える。
import math
from statistics import mean
print(math.sqrt(16)) # 4.0
print(math.ceil(3.2)) # 4
print(mean([10, 20, 30])) # 20
# 別名を付ける
import math as m
print(f"{m.pi:.2f}") # 3.14
# 自作モジュール(同じフォルダに utils.py を置いた場合)
# import utils
# print(utils.with_tax(1000))
3基本ドリル(10問)
出力 == 4.0
import math してから math.sqrt(16)。
import math print(math.sqrt(16))
平方根の計算式を自分で書く必要はない。まず標準ライブラリに無いか探すのがPythonの作法。
A. sqrt(16) B. math.sqrt(16) C. math(sqrt(16)) D. import.sqrt(16) 選択★☆☆無料
解答 == B
import した場合、関数の前に何を付けるか。
B
import math だけでは sqrt() 単体は使えない。直接書きたければ from math import sqrt が必要。
出力 == 4
from math import ceil と書けば ceil(3.2) と直接呼べる。
from math import ceil print(ceil(3.2))
ceil は切り上げ、floor は切り捨て。int() は小数を捨てるだけなので、負の数では floor と結果が変わる点に注意。
____ statistics import mean print(mean([10, 20, 30]))
出力 == 20
「〜から取り込む」を表すキーワード。
from
statistics には mean のほか median(中央値)、mode(最頻値)、stdev(標準偏差)がある。集計処理で自前計算する前に確認したい。
A. import utils.py B. import utils C. import "utils.py" D. from utils.py 選択★☆☆無料
解答 == B
拡張子は書くのか、書かないのか。
B
.py は付けないのがルール。ファイル名がそのままモジュール名になるので、ファイル名にハイフンや日本語を使わないこと。
出力 == 3.14
import math as m。表示は f"{m.pi:.2f}"。
import math as m
print(f"{m.pi:.2f}")
別名は長いモジュール名を短くするために使う。実務では pandas を pd、numpy を np と書くのが世界共通の慣習。
def hello():
return "こんにちは"
____ == "__main__":
print(hello())
出力 == こんにちは
特殊変数 __name__ を使った定型の1行。
if __name__
この1行はほぼ定型句として覚えてよい。アンダースコアは前後に2つずつで計4つ。
A. 常に実行される B. 直接実行したときだけ実行され、importされたときは実行されない C. importされたときだけ実行される D. 実行されない 選択★★☆無料
解答 == B
モジュールとして読み込まれたときに動いてほしくない処理は何か。
B
これが無いと、import しただけでテスト用の print が全部走る。モジュールを作るときは必ず付ける。
出力 == 10
PY11で学んだファイル書き込みで calc.py を作る。書き終わってから import calc する。
with open("calc.py", "w", encoding="utf-8") as f:
f.write("def add(a, b):\n return a + b\n")
import calc
print(calc.add(3, 7))
モジュールの正体はただの .py ファイル。特別な仕組みではなく、同じフォルダに置いて名前で呼ぶだけ。
出力 == 82.5 / 85(2行)
statistics.mean() と statistics.mode()。
import statistics scores = [70, 85, 90, 85] print(statistics.mean(scores)) print(statistics.mode(scores))
最頻値を自分で書くとPY07の辞書集計が必要になるが、mode() なら1行。車輪の再発明を避けるのが実務の生産性を決める。
4実践シナリオ(5問)
出力2行が完全一致
モジュールの中身は行のリストを作って "\n".join(lines) で書き出すと読みやすい。書き終えてから import utils する。
lines = [
"def with_tax(price, rate=0.1):",
" return int(price * (1 + rate))",
"",
"",
"def shipping_fee(price):",
" if price >= 5000:",
" return 0",
" return 600",
]
with open("utils.py", "w", encoding="utf-8") as f:
f.write("\n".join(lines))
import utils
for p in [4800, 12000]:
print(f"{p:,}円 → 税込{utils.with_tax(p):,}円 / 送料{utils.shipping_fee(p)}円")
PY08で作った関数を別ファイルに移すだけでモジュールになる。こうしておけば他のスクリプトからも同じ計算を呼べる。
出力3行が完全一致
設定値は大文字で書くのが慣習。税率の表示は {x:.0%} でパーセント表記になる。
lines = [
'SHOP_NAME = "ゼロカラショップ"',
"TAX_RATE = 0.1",
"FREE_SHIPPING = 5000",
]
with open("config.py", "w", encoding="utf-8") as f:
f.write("\n".join(lines))
import config
print(config.SHOP_NAME)
print(f"税率:{config.TAX_RATE:.0%}")
print(f"送料無料ライン:{config.FREE_SHIPPING:,}円")
変わる値をコードから追い出すのが設定分離の目的。税率が変わっても config.py の1行を直すだけで、全スクリプトに反映される。
出力3行が完全一致
statistics.mean() と statistics.median()、切り上げは math.ceil()。平均は {x:.1f} で表示する。
import math
import statistics
scores = [72, 85, 91, 68]
print(f"平均:{statistics.mean(scores):.1f}")
print(f"中央値:{statistics.median(scores)}")
print(f"平均の切り上げ:{math.ceil(statistics.mean(scores))}")
import は1行に1つ、標準ライブラリを先に、アルファベット順に並べるのが読みやすい書き方(PEP8)。中央値は平均と違い外れ値に強い指標。
出力2行が完全一致
フォルダ作成は os.makedirs("mypkg", exist_ok=True)。ファイルパスは "mypkg/tax.py" のように書く。__init__.py は中身が空でよい。
import os
os.makedirs("mypkg", exist_ok=True)
with open("mypkg/__init__.py", "w", encoding="utf-8") as f:
f.write("")
lines = [
"def with_tax(price, rate=0.1):",
" return int(price * (1 + rate))",
]
with open("mypkg/tax.py", "w", encoding="utf-8") as f:
f.write("\n".join(lines))
from mypkg import tax
for p in [1000, 5000]:
print(f"{p:,}円 → {tax.with_tax(p):,}円")
パッケージ=モジュールを入れたフォルダ。機能が増えてファイルが散らかってきたら、種類ごとにフォルダへまとめる。__init__.py は「このフォルダはパッケージです」という目印。
出力4行が完全一致
import しただけなら __name__ は "__main__" ではなくモジュール名("check")になるので、ガードの中は実行されない。
lines = [
"def double(n):",
" return n * 2",
"",
"",
'if __name__ == "__main__":',
' print("これはテスト出力です")',
]
with open("check.py", "w", encoding="utf-8") as f:
f.write("\n".join(lines))
import check
print("importしました")
print("テスト出力は実行されていません")
print(f"double(5) = {check.double(5)}")
print(f"check.__name__ = {check.__name__}")
「これはテスト出力です」が表示されないことがこの問題の答え。__name__ には直接実行時は "__main__"、import時はモジュール名が入る。この違いがガードの正体。
5仕上げ課題
① config.py を作る — SHOP_NAME = "ゼロカラ商店" / TAX_RATE = 0.1 / MEMBER_DISCOUNT = 0.1
② billing.py を作る — 中で import config し、3つの関数を定義
・subtotal(price, qty) … 単価×数量
・apply_discount(amount, is_member) … 会員なら MEMBER_DISCOUNT ぶん引く(整数に切り捨て)
・with_tax(amount) … TAX_RATE ぶん加算(整数に切り捨て)
③ 本体で両方を import し、以下のデータで請求書を出力
items = [("ノートPC", 128000, 1), ("マウス", 3200, 2), ("USBメモリ", 1500, 3)] / is_member = True
出力仕様(9行):
=== ゼロカラ商店 請求書 ===
ノートPC:128,000円 × 1 = 128,000円
マウス:3,200円 × 2 = 6,400円
USBメモリ:1,500円 × 3 = 4,500円
---
小計:138,900円
会員割引後:125,010円
消費税込:137,511円
(税率10% / 会員割引10%)
出力9行が完全一致
モジュールの中身は行のリストを "\n".join() で書き出す。billing.py の先頭で import config すると、billing の中から config.TAX_RATE を参照できる。本体側では import config と import billing の両方が必要。
config_lines = [
'SHOP_NAME = "ゼロカラ商店"',
"TAX_RATE = 0.1",
"MEMBER_DISCOUNT = 0.1",
]
with open("config.py", "w", encoding="utf-8") as f:
f.write("\n".join(config_lines))
billing_lines = [
"import config",
"",
"",
"def subtotal(price, qty):",
" return price * qty",
"",
"",
"def apply_discount(amount, is_member):",
" if is_member:",
" return int(amount * (1 - config.MEMBER_DISCOUNT))",
" return amount",
"",
"",
"def with_tax(amount):",
" return int(amount * (1 + config.TAX_RATE))",
]
with open("billing.py", "w", encoding="utf-8") as f:
f.write("\n".join(billing_lines))
import config
import billing
items = [("ノートPC", 128000, 1), ("マウス", 3200, 2), ("USBメモリ", 1500, 3)]
is_member = True
print(f"=== {config.SHOP_NAME} 請求書 ===")
total = 0
for name, price, qty in items:
line = billing.subtotal(price, qty)
total += line
print(f"{name}:{price:,}円 × {qty} = {line:,}円")
discounted = billing.apply_discount(total, is_member)
taxed = billing.with_tax(discounted)
print("---")
print(f"小計:{total:,}円")
print(f"会員割引後:{discounted:,}円")
print(f"消費税込:{taxed:,}円")
print(f"(税率{config.TAX_RATE:.0%} / 会員割引{config.MEMBER_DISCOUNT:.0%})")
PY08と出力は同じだが構造が違うのがこの課題の要点。税率変更は config.py の1行、計算ロジックの修正は billing.py だけ、表示の変更は本体だけ——直す場所が役割ごとに決まっている状態を作れた。これが「大きなプログラムを作る」ということで、ファイルが10個100個に増えても破綻しない設計の基礎になる。