第7回では、while文とinput()を使って、
qが押されるまで、コーヒーや釣りのログを入力し続ける- 入力されたログをCSVに追記する
という、小さな「ログ入力ツール」を作りました。
ただ、コードを見直してみると、こんな感覚が出てきませんか?
- CSVに書き込むところ、何度も同じようなコードを書いているな…
- ログ1件分の辞書を作るところも、かなりパターンが似ている
この 「同じような処理をまとめたい」 という感覚は、
関数(function) に進むタイミングの合図です。
今回のテーマは、
よく使う処理に名前をつけて、コードをスッキリさせること。
コーヒー&釣りログのコードを実際にリファクタしながら、
- 関数の基本(def / 引数 / return)
- 関数に「1つの役割」を持たせる考え方
- 後で例外処理(try / except)やクラスを組み込むための土台
を、一緒に作っていきます。
この回のゴールと全体像
第8回のゴールは、次の4つです。
- 関数とは何か(「処理に名前をつける箱」)というイメージが持てる
def/ 引数 /returnの基本的な使い方がわかる- コーヒー&釣りログのコードから「関数に切り出せる部分」を見つけて整理できる
- 「関数の中で try / except を使って、エラー処理をまとめる」イメージが持てる
この先、
- 第9回:例外処理入門(エラーと仲良くなる回)
- 第10回:クラス超入門(ログをオブジェクトとして扱う)
に進んでいくための土台にもなります。
関数とは? よく使う処理にラベルを貼る
関数はひと言でいうと、
「よく使う処理に名前をつけたもの」
です。
例えば、コーヒーを淹れるときの手順をノートに書くと、
- 豆を量る
- 挽く
- お湯を沸かす
- 蒸らす
- 少しずつお湯を注ぐ
という細かいステップになりますが、
会話の中ではまとめて
「コーヒー淹れてくるね」
で済ませますよね。
関数もこれと同じで、
- 細かい処理のステップを1つにまとめて
- 「この名前を呼んだら、まとめてやってね」
とPythonに頼むための仕組みです。
関数の基本形
def 関数名(引数1, 引数2, ...):
処理
return 結果
def:関数を定義しますよ、という合図関数名:その処理に付ける名前引数:外から受け取る値(材料)return:外に返す値(結果)
という構造になっています。
例:スコアからコメントを返す関数
def comment_for_score(score):
if score >= 4.5:
return "かなり特別な一杯。記念すべきレベル。"
elif score >= 4.0:
return "安定して美味しい。リピートしたい。"
elif score >= 3.0:
return "普通に美味しい。気分次第でまた飲むかも。"
else:
return "好みとは少し違うかもしれない。"
使う側はこうです。
score = 4.2
comment = comment_for_score(score)
print("スコア:", score)
print("コメント:", comment)
中の if 文がどれだけ長くても、
呼び出し側から見るとたった1行で済むようになります。
まずは「ファイル1つ」で完結する関数の例
いきなりコーヒーログに組み込むとイメージがつきにくいので、
まずは 1つのファイルの中だけで完結する、いちばん小さい関数の例 を見てみます。
sample_function.py を作って実行してみる
VSCodeで、新しく sample_function.py というファイルを作り、次のコードを書きます。
def hello():
print("こんにちは、関数の世界!")
# ここから下が「実行される部分」
hello()
ポイント:
- 上の
def hello():で 関数を定義 - 下の
hello()の行で 関数を呼び出す(実行する)
ターミナルで、このファイルがあるフォルダに移動してから:
python3 sample_function.py
を実行すると、
こんにちは、関数の世界!
と表示されます。
この流れが関数の最小パターンです。
- 上の方で
def ...で関数を「用意」しておく - 下の方で
関数名()と書いて「実行」する
引数と return つきの関数も同じ流れで動く
もう少しだけ進んだ例も見てみます。
def add(a, b):
result = a + b
return result
x = add(3, 5)
print("3 + 5 の結果は:", x)
やっていることは、
addという名前の関数を定義aとbという 引数(外から渡す値) を受け取るreturnで「計算した結果」を呼び出し元に返す
というだけです。
実行方法はさきほどと同じで、
python3 sample_function.py
のように python ファイル名.py でOKです。
これがわかっていれば、このあとの「コーヒーログを関数で整理する」の実行もイメージしやすくなります。
1件分のコーヒーログを作る処理を関数にする
第7回の coffee_input.py では、
while ループの中にこういう処理を書いていました。
name = input("コーヒー名を入力してください(終了するには q):")
# ...
roast = input("焙煎度:")
memo = input("ひとことメモ:")
score_str = input("スコア(0〜5の数字):")
# try / except で score を float に変換
# log 辞書を作って append
これを「1件分のコーヒーログを作る関数」として切り出してみます。
入力 → 変換 → 辞書 にする関数
def input_one_coffee_log():
"""1件分のコーヒーログを入力して辞書にして返す関数"""
name = input("コーヒー名を入力してください(終了するには q):")
if name == "q":
return None # 終了の合図として None を返す
roast = input("焙煎度(浅煎り・中煎り・深煎りなど):")
memo = input("ひとことメモ:")
score_str = input("スコア(0〜5の数字):")
# ここで本当は try / except をしっかり書きたい。
# 第7回では軽く触れましたが、例外処理は第9回で1話分じっくり扱う予定です。
try:
score = float(score_str)
except ValueError:
print("数値に変換できなかったので、スコアを 3.0 にします。")
score = 3.0
log = {
"name": name,
"roast": roast,
"memo": memo,
"score": score
}
return log
こうしておくと、while ループ側はかなりスッキリします。
while ループ側から見るとこうなる
coffee_logs = []
while True:
log = input_one_coffee_log()
if log is None:
print("入力を終了します。")
break
coffee_logs.append(log)
print("1件ログを追加しました。")
print("----------------------")
入力 → 辞書作成 → スコア変換 → ログ作成
までのゴチャゴチャした処理は関数の中に隠れます。
while 側は「1件ログをもらう/None なら終わる」という
ストーリーだけ を読めばよくなります。
CSVに書き込む処理も関数にする
同じように、CSVに書き込む部分も
「ファイル名・フィールド名・ログのリスト」を受け取って書くだけの関数
にすると再利用しやすくなります。
複数のログをCSVに追記する関数
import csv
import os
def append_logs_to_csv(filename, fieldnames, logs):
"""ログのリストをCSVに追記する関数"""
if not logs:
print("書き込むログがありません。")
return
file_exists = os.path.exists(filename)
with open(filename, "a", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
# ファイルがまだなければヘッダーを書く
if not file_exists:
writer.writeheader()
writer.writerows(logs)
print(f"{filename} に {len(logs)} 件のログを書き込みました。")
コーヒーログ側から使う
# coffee_functions.py などにまとめてもよい
FIELDNAMES_COFFEE = ["name", "roast", "memo", "score"]
coffee_logs = []
while True:
log = input_one_coffee_log()
if log is None:
break
coffee_logs.append(log)
append_logs_to_csv("coffee_logs.csv", FIELDNAMES_COFFEE, coffee_logs)
コーヒーログツールを関数で整理した全体像
ここまでバラバラに関数の例を見てきたので、
実際に 1つのファイルとして完成した形 を載せておきます。
ファイル名は coffee_logger.py としてみましょう。
# coffee_logger.py
import csv
import os
def input_one_coffee_log():
"""1件分のコーヒーログを入力して辞書にして返す関数"""
name = input("コーヒー名を入力してください(終了するには q):")
if name == "q":
return None # 終了の合図として None を返す
roast = input("焙煎度(浅煎り・中煎り・深煎りなど):")
memo = input("ひとことメモ:")
score_str = input("スコア(0〜5の数字):")
# ★ 本格的な例外処理(try / except)の話は第9回でじっくり扱います。
try:
score = float(score_str)
except ValueError:
print("数値に変換できなかったので、スコアを 3.0 にします。")
score = 3.0
log = {
"name": name,
"roast": roast,
"memo": memo,
"score": score,
}
return log
def append_logs_to_csv(filename, fieldnames, logs):
"""ログのリストをCSVに追記する関数"""
if not logs:
print("書き込むログがありません。")
return
file_exists = os.path.exists(filename)
with open(filename, "a", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
# ファイルがまだなければヘッダーを書く
if not file_exists:
writer.writeheader()
writer.writerows(logs)
print(f"{filename} に {len(logs)} 件のログを書き込みました。")
def main():
"""このスクリプト全体のメインの流れ"""
FIELDNAMES_COFFEE = ["name", "roast", "memo", "score"]
filename = "coffee_logs.csv"
coffee_logs = []
while True:
log = input_one_coffee_log()
if log is None:
print("入力を終了します。")
break
coffee_logs.append(log)
print("1件ログを追加しました。")
print("----------------------")
append_logs_to_csv(filename, FIELDNAMES_COFFEE, coffee_logs)
# このファイルを「直接実行したときだけ」main() を呼ぶおまじない
if __name__ == "__main__":
main()
coffee_logger.py の実行方法
VSCodeで coffee_logger.py を作り、上のコードを丸ごと貼る
ターミナルで、このファイルがあるフォルダに移動する
次のコマンドを実行:
- VSCodeで
coffee_logger.pyを作り、上のコードを丸ごと貼る - ターミナルで、このファイルがあるフォルダに移動する
- 次のコマンドを実行:
python3 coffee_logger.py
- 画面の指示に従ってコーヒー名などを入力
- 入力をやめたいときは、コーヒー名のところで
qと入力してEnter
実行が終わったあと、同じフォルダに coffee_logs.csv ができていれば成功です。
以降は何度でも python coffee_logger.py を実行して、
コーヒーを飲むたびにログを少しずつ積み上げていけます。
釣りログ用の「1件作る関数」と組み合わせる
釣りログでも、同じ append_logs_to_csv を再利用できます。
def input_one_fishing_log():
"""1件分の釣りログを入力して辞書にして返す関数"""
date = input("日付(例:2025/05/01、終了するには q):")
if date == "q":
return None
lake = input("場所(湖の名前など):")
fish_type = input("魚種(ブラウン・レイクなど):")
length_str = input("サイズ(cm):")
is_released_str = input("リリースしましたか?(y/n):")
try:
length = int(length_str)
except ValueError:
print("整数に変換できなかったので、サイズを 0cm とします。")
length = 0
is_released = (is_released_str.lower() == "y")
log = {
"date": date,
"lake": lake,
"fish_type": fish_type,
"fish_length_cm": length,
"is_released": is_released
}
return log
FIELDNAMES_FISHING = ["date", "lake", "fish_type", "fish_length_cm", "is_released"]
fishing_logs = []
while True:
log = input_one_fishing_log()
if log is None:
break
fishing_logs.append(log)
append_logs_to_csv("fishing_logs.csv", FIELDNAMES_FISHING, fishing_logs)
こうして見ると、
- 「コーヒー用」と「釣り用」の違いは
- どんな項目を入力するか
- 辞書にどんなキーを持たせるか
- CSVに書き込むロジックそのものは共通
という構造がはっきり見えてきます。
関数を作ることで、「同じパターン」と「違い」が見つけやすくなります。
関数の中で try / except を使う意味
第7回・第8回では、一部のコードで
try:
score = float(score_str)
except ValueError:
print("数値に変換できなかったので、スコアを 3.0 にします。")
score = 3.0
のように try / except を使いました。
今はまだ「ざっくり使っているだけ」ですが、
関数の中にこのようなエラー処理を閉じ込めておくと、使う側が楽になります。
エラー処理を「関数の中に隠す」イメージ
例えば、関数の外側から見れば、
log = input_one_coffee_log()
と書いているだけで、
- input() で文字列を受け取る
float()/int()への変換でエラーが出るかもしれない- そのときにどうフォローするか
といった細かな判断は、関数の中に閉じ込められます。
この、
「エラーが起きるかもしれない細かいところは関数の中に押し込めて、
関数の外側は“きれいな物語”にしておく」
という考え方は、例外処理を学ぶときにも、クラスを学ぶときにも、
とても大事な土台になります。
例外処理を深か掘る
ここまでで、
- 第7回:while の中で try / except を「ちょっとだけ」使う
- 第8回:関数の中に try / except を閉じ込めるイメージを持つ
というところまできました。
ただ、「例外処理(エラー処理)」そのものは、
1話分ゆっくりやったほうが絶対に理解しやすいテーマです。
なので、このシリーズでは、
第9回を「例外処理入門」として解説します
予定している内容は、例えばこんな感じです。
- 例外とは何か?エラーとどう違う?
try/except/else/finallyの基本形- どこまでを「エラー」として扱い、どこからを「正常系」にするか
- ログ入力ツールにおける「ユーザー入力のゆるい扱い方」
- 例外を「飲み込む」のではなく、ログに残したり上に投げたりする考え方
関数を先に押さえたことで、
- 「この関数の中で try / except をどう書くか」
- 「呼び出し側はどう振る舞ってほしいか」
という視点で、例外処理の話がしやすくなりました。
さらにその先はクラスへと続く
関数までたどり着くと、次に見えてくるのが クラス(class) です。
これまでの流れを整理すると:
- 変数・リスト・辞書 → 「データ」を扱えるようになった
- if・for・while → 「流れ・条件・くり返し」を扱えるようになった
- 関数 → 「よく使う処理」をひとかたまりにして名前をつけられるようになった
ここからクラスに進むときの自然な一歩は、
「データ(ログ)と、そのデータに関する処理(メソッド)を、1つのまとまりとして扱いたい」
という欲求です。
例えば:
CoffeeLogというクラスを作って- プロパティとして
name,roast,memo,scoreを持ち to_dict()でCSV用の辞書を返すcomment()でスコアに応じたコメントを返す
- プロパティとして
こんなふうに、
- 「1件分のログ」という“もの”
- それに対する操作(処理)
をひとまとめにするのがクラスです。
関数の回を挟んだことで、
- 「処理に名前をつけて外出しする」
という感覚ができています。
次にクラスを学ぶときは、
- 「データ+そのデータ向けの関数」をまとめる箱
として捉えると、とてもスムーズに入っていけます。
今日のまとめ 関数でログツールが「少しだけ大人になる」
今回は、
- 関数とは「よく使う処理に名前をつける箱」という話
def/ 引数 /returnの基本- 1件分のログ入力処理を
input_one_coffee_log()/input_one_fishing_log()に切り出す - 複数ログをCSVに追記する
append_logs_to_csv()を作る - 関数の中に try / except を閉じ込めるイメージ
- 第9回で「例外処理入門」を1話まるごとやる計画
- その先に「クラスでログをオブジェクトとして扱う」流れがあること
を見てきました。
同じコーヒー・同じブラウントラウトのログでも、
- ただ動けばいいスクリプト
から - 役割ごとに関数に分かれた、育てやすいツール
へと少し成長したはずです。
次回予告 – 第9回:例外処理入門「エラーと仲良くなる」
第9回は、
エラーと仲良くなる
をテーマに、
- 例外(Exception)とは何か
try/except/else/finallyの基本形- 「ここまではユーザーの入力ミスとしてやさしく扱う」
「ここからは本当に危ないエラーだから止める」
といった線引き - ログ入力ツールに「エラー時の振る舞い」をどう埋め込むか
を、コーヒー&釣りログのコードを使いながら丁寧に解説します。
例外処理を1話かけて押さえたあと、
- データと処理をまとめる クラス超入門
に進むことで、
- 「現実の世界(湖・コーヒー・日々の記録)」
を、 - 「Pythonの世界のオブジェクト」として扱えるようになっていきます。
引き続き、湖とコーヒーと星空のそばで、
少しずつPythonの世界を広げていきましょう。




コメント