Lecture 1Pythonとは何か — プログラミングの世界への第一歩

10:00

Pythonとは何か — プログラミングの世界への第一歩

なぜ今Pythonなのか

2024年のTIOBE Index(プログラミング言語の人気ランキング)で、Pythonは初めてC言語を抜いて1位に立ちました。Stack Overflowの2024年Developer Surveyでも、「これから学びたい言語」の1位がPythonです。

この人気の理由は明確で、Pythonが「読みやすく、書きやすく、できることが多い」言語だからです。Instagram、YouTube、Spotify、Netflix — これらのサービスはすべてPythonをバックエンドの一部に使っています。NASAは宇宙探査機のデータ解析にPythonを使い、CERNは素粒子物理学の研究にPythonを活用しています。

もちろん、Web開発ならJavaScript、iOSアプリならSwift、システムプログラミングならRustといった、用途に特化した言語もあります。しかし「最初の1言語」として、Pythonほどバランスの良い選択肢はありません。

プログラミングとは何か — 誤解を解く

プログラミングを始める前に、よくある誤解を3つ解いておきます。

誤解 実際
「数学が得意じゃないとダメ」 日常のプログラミングで高度な数学はほぼ使わない。四則演算と論理的思考ができれば十分
「若い人しか覚えられない」 30代・40代から始めてプロになった人は多数。重要なのは年齢ではなく継続する仕組み
「暗記力が必要」 プロのエンジニアも毎日ググっている。暗記ではなく「調べ方を知っている」ことが大事

プログラミングの本質は「コンピュータへの指示書を書くこと」です。料理のレシピを思い浮かべてください。「玉ねぎを切る → 油で炒める → 塩を振る」という手順を、コンピュータが理解できる形で書いたものがプログラムです。

コンピュータは人間と違い、曖昧な指示を理解できません。「適量の塩」ではなく「3グラムの塩」と書く必要があります。この「曖昧さをなくす」訓練が、プログラミング学習の核心です。

Pythonの歴史と設計思想

Pythonは1991年にオランダのプログラマー、グイド・ヴァンロッサム(Guido van Rossum)によって公開されました。名前の由来はヘビではなく、イギリスのコメディ番組「Monty Python's Flying Circus」です。

ヴァンロッサムがPythonを設計する際に最も重視したのが「読みやすさ」です。この思想はPythonの公式ドキュメントに「The Zen of Python」として記されています。その中でも特に重要な原則がこちらです:

  • Readability counts(読みやすさは重要) — コードは書く時間より読む時間の方が長い
  • There should be one obvious way to do it(やり方は1つであるべき) — 選択肢が多すぎると迷う
  • Simple is better than complex(シンプルが複雑に勝る) — 必要以上に凝らない

他の言語と比較すると、Pythonの「読みやすさ重視」は一目瞭然です。例えば「Hello, World!」を画面に表示する最も基本的なプログラムを見てみましょう。

Java:   System.out.println("Hello, World!");
C:      printf("Hello, World!\n");
Python: print("Hello, World!")

Pythonが最もシンプルです。この差は小さく見えますが、数千行のプログラムになると読みやすさの差は劇的に広がります。

Pythonでできること — 5つの代表的な用途

Pythonの応用範囲は極めて広く、1つの言語を学ぶだけで多くの分野に進出できます。

1. データ分析・可視化 pandas、matplotlib、NumPyといったライブラリを使えば、Excelでは処理しきれない大量データの分析やグラフ作成が可能です。実際、金融機関のアナリストやマーケティング担当者がPythonでデータ分析を行うケースは年々増えています。

2. AI・機械学習 TensorFlow(Google開発)、PyTorch(Meta開発)といったAIフレームワークはPythonで書かれています。ChatGPTの学習にもPythonが使われました。AI分野でPythonは事実上の標準言語です。

3. Web開発 Django(InstagramやPinterestが使用)やFlaskといったフレームワークで、Webアプリケーションを構築できます。

4. 業務自動化 毎日のExcelレポート作成、ファイルの整理、メール送信、Webスクレイピングなど、手作業で行っていた業務を自動化できます。「1時間かかっていた作業が10秒で終わる」体験は、プログラミング学習の最初のモチベーションになります。

5. 科学技術計算 天文学、生物学、物理学などの研究者が、シミュレーションやデータ処理にPythonを使っています。NASAのジェット推進研究所(JPL)ではPythonが標準ツールの1つです。

実践ワーク:Pythonを体験してみよう

まだ環境構築は次回ですが、今すぐPythonを試す方法があります。ブラウザで以下のサイトにアクセスしてください:

Google Colaboratory(https://colab.research.google.com/)

Googleアカウントがあれば、インストール不要でPythonを実行できます。「ノートブックを新規作成」をクリックし、セルに以下を入力してShift+Enterを押してください:

# 自分の名前を表示する("太郎"を自分の名前に変えてください)
name = "太郎"
print(f"こんにちは、{name}さん!Pythonの世界へようこそ!")

# 簡単な計算
print(f"1 + 1 = {1 + 1}")
print(f"100 × 3.14 = {100 * 3.14}")

実行すると、画面に挨拶と計算結果が表示されるはずです。これがあなたの最初のPythonプログラムです。name = "太郎" の部分を変えると、表示される名前が変わります。これが「変数」の概念で、第3回で詳しく学びます。

この講座の全体像と学習の進め方

テーマ 身につくスキル
1 Pythonとは(本講義) 全体像の理解、Google Colabでの実行
2 環境構築 Python本体のインストール、VS Codeの設定
3 変数とデータ型 数値・文字列・リストの操作
4 条件分岐 if/elif/elseで処理を分岐させる
5 繰り返し for/whileで同じ処理を繰り返す
6 関数 処理をまとめて名前をつける
7 辞書とセット キーと値のペアでデータを管理
8 ファイル操作 CSV・テキストファイルの読み書き
9 エラーハンドリング 例外処理とデバッグの技法
10 総合演習 住所録管理アプリの作成

この講座を終える頃には、「自分でPythonスクリプトを書いて、日常の作業を自動化できる」レベルを目指します。プログラミング経験は一切不要ですが、「自分で手を動かす」ことが最も重要です。コードは見るだけでなく、必ず自分で打ち込んで実行してください。

次回の準備: Google Colaboratoryにアクセスして、上の実践ワークを実際に試しておいてください。次回はPythonをPC本体にインストールして、本格的な開発環境を整えます。

参考文献: - Al Sweigart『退屈なことはPythonにやらせよう 第2版』(オライリー・ジャパン、2023年) - TIOBE Index(https://www.tiobe.com/tiobe-index/) - Stack Overflow Developer Survey 2024(https://survey.stackoverflow.co/2024/)

Lecture 2環境構築 — Pythonのインストールと最初のプログラム

12:00

環境構築 — Pythonのインストールと最初のプログラム

なぜ環境構築が重要なのか

プログラミング学習で最初の挫折ポイントは、意外にも「環境構築」です。Stack Overflowの調査によると、プログラミング初心者の約30%が「開発環境のセットアップで躓いた」と回答しています。

前回はGoogle Colaboratoryを使いましたが、本格的にPythonを学ぶには、自分のPCにPythonをインストールし、コードエディタを設定する必要があります。この回では、Windows・Mac両方の手順を丁寧に解説します。一度セットアップすれば、以降はすべてこの環境で学習を進められます。

Step 1: Pythonのインストール

Windowsの場合

  1. python.org(https://www.python.org/downloads/)にアクセス
  2. 「Download Python 3.x.x」ボタンをクリック(3.12以降を推奨)
  3. ダウンロードしたインストーラを実行
  4. 最重要: インストール画面の下部にある 「Add python.exe to PATH」にチェックを入れる
  5. 「Install Now」をクリック

「Add to PATH」のチェックを忘れると、コマンドプロンプトからpythonコマンドが使えません。忘れた場合は再インストールするのが最も確実です。

Macの場合

MacにはPython 2がプリインストールされていますが、これは古いバージョンです。Python 3を別途インストールします。

  1. python.orgから最新版をダウンロード
  2. .pkgファイルを実行してインストール

またはターミナルでHomebrewを使う方法もあります:

brew install python3

インストール確認

Windows: コマンドプロンプトを開き、Mac: ターミナルを開き、以下を入力:

python --version

Python 3.12.xのように表示されれば成功です。Macでpython3 --versionが必要な場合もあります。

Step 2: コードエディタ — VS Codeの導入

プログラムを書くには「コードエディタ」が必要です。メモ帳でも書けますが、プロの開発者が使う専用エディタを最初から使うことを強く推奨します。

Visual Studio Code(VS Code) がベストな選択です。理由は3つあります:

特徴 説明
無料 Microsoftが無料で提供。商用利用も可
拡張機能 Python専用の拡張機能で、エラー表示・自動補完が使える
世界シェア1位 Stack Overflow 2024調査で開発者の73%が使用。情報が豊富

インストール手順

  1. code.visualstudio.comにアクセス
  2. OS に合ったバージョンをダウンロード・インストール
  3. VS Codeを起動し、左サイドバーの拡張機能アイコン(四角が4つ)をクリック
  4. 検索欄に「Python」と入力し、Microsoftの公式Python拡張機能をインストール
  5. 同様に「Japanese Language Pack」を検索してインストール(日本語化)

Python拡張機能をインストールすると、以下の機能が使えるようになります: - 構文ハイライト: コードが色分けされ、読みやすくなる - 自動補完(IntelliSense): 途中まで入力すると候補が表示される - エラー検出: タイプミスを赤線で教えてくれる - デバッグ機能: プログラムを1行ずつ実行して動作を確認できる

Step 3: 最初のPythonファイルを作成する

いよいよ実際にプログラムを書きます。

  1. デスクトップ(または好きな場所)に「python-learning」フォルダを作成
  2. VS Codeで「ファイル → フォルダーを開く」からそのフォルダを選択
  3. 左サイドバーの「新しいファイル」アイコンをクリック
  4. ファイル名を hello.py と入力(.pyがPythonファイルの拡張子)

hello.pyに以下のコードを入力してください:

# 私の最初のPythonプログラム
print("Hello, World!")
print("Pythonプログラミングを始めます")

# 簡単な計算
tax_rate = 0.10
price = 1000
tax = price * tax_rate
total = price + tax

print(f"商品価格: {price}円")
print(f"消費税: {tax}円")
print(f"合計: {total}円")

Step 4: プログラムを実行する

方法1: VS Code内のターミナル

  1. VS Codeの上部メニューから「ターミナル → 新しいターミナル」を選択
  2. 画面下部にターミナルが表示される
  3. 以下を入力してEnter:
python hello.py

方法2: 実行ボタン

VS Codeの右上にある「▷」(再生ボタン)をクリックしても実行できます。Python拡張機能をインストールしていれば、このボタンが表示されます。

実行結果

Hello, World!
Pythonプログラミングを始めます
商品価格: 1000円
消費税: 100.0円
合計: 1100.0円

この表示が出れば、環境構築は完了です。あなたのPCで、自分で書いたPythonプログラムが動きました。

実践ワーク: 自己紹介プログラムを作ろう

新しいファイル self_intro.py を作成し、以下を自分用にカスタマイズして実行してください:

# 自己紹介プログラム
name = "あなたの名前"
age = 30  # あなたの年齢
hobby = "あなたの趣味"
reason = "Pythonを学びたい理由"

print("=" * 40)
print("  自己紹介カード")
print("=" * 40)
print(f"名前: {name}")
print(f"年齢: {age}歳")
print(f"趣味: {hobby}")
print(f"Python学習の動機: {reason}")
print("=" * 40)

ポイントは、各行の意味を推測しながら値を変えてみることです。"=" * 40は何をしているでしょう? printf"..."の中の{}は何をしているでしょう? 次回の「変数とデータ型」で正式に学びますが、今の段階で直感的に触れておくと理解が早まります。

トラブルシューティング

環境構築でよく遭遇するエラーと対処法をまとめます。

エラー 原因 対処法
'python' は認識されていません PATHが通っていない Pythonを再インストールし「Add to PATH」にチェック
SyntaxError: invalid syntax 全角スペースや全角括弧を使っている エディタの文字を半角に修正。日本語入力をオフに
ModuleNotFoundError ライブラリ未インストール pip install ライブラリ名 を実行
VS Codeでpythonが見つからない インタプリタ未選択 Ctrl+Shift+P →「Python: Select Interpreter」で選択

特に日本語環境で多いのが「全角スペース問題」です。プログラムのインデント(字下げ)に全角スペースを使うと、見た目は正しくてもエラーになります。VS Codeの設定で「全角スペースの可視化」を有効にすると防げます。

まとめと次回の準備

今回のポイント: - Python公式サイトからインストール。Add to PATHを忘れない - VS Code + Python拡張機能 が標準的な開発環境 - .pyファイルに書いてpython ファイル名.pyで実行 - 全角スペースはエラーの元。半角で統一

次回: 変数とデータ型を学びます。数値、文字列、リストという3つの基本データ型を使って、データを自在に操作する方法を身につけます。

参考文献: - Python公式ドキュメント(https://docs.python.org/ja/3/) - VS Code公式サイト(https://code.visualstudio.com/) - 『Pythonスタートブック 増補改訂版』辻 真吾(技術評論社、2018年)

Lecture 3変数とデータ型 — 数値・文字列・リストの基本

12:00

変数とデータ型 — 数値・文字列・リストの基本

変数とは「名前のついた箱」

前回の実践ワークでname = "太郎"と書きました。このnameが「変数」です。変数はプログラミングの最も基本的な概念で、「データに名前をつけて保存する仕組み」です。

age = 25          # 整数(int)を保存
height = 170.5    # 小数(float)を保存
name = "田中"     # 文字列(str)を保存
is_student = True # 真偽値(bool)を保存

変数の名前には明確なルールがあります:

ルール OK NG
英数字とアンダースコア user_name, age2
数字で始めない item1 1item
予約語は使えない my_list list, print, if
大文字小文字は区別される Namenameは別物

Python公式のスタイルガイド「PEP 8」では、変数名にスネークケース(小文字+アンダースコア)を推奨しています。userNameではなくuser_nameが Pythonicな書き方です。

数値型 — 計算の基礎

Pythonの数値型は主に2種類です。

int(整数): 10, -3, 0, 1000000 float(浮動小数点数): 3.14, -0.5, 1.0

四則演算はそのまま書けます:

a = 10
b = 3

print(a + b)   # 13 (加算)
print(a - b)   # 7  (減算)
print(a * b)   # 30 (乗算)
print(a / b)   # 3.3333... (除算 → 結果はfloat)
print(a // b)  # 3  (切り捨て除算 → 結果はint)
print(a % b)   # 1  (剰余:余り)
print(a ** b)  # 1000 (べき乗:10の3乗)

初心者が最もつまずくのが /(除算)と //(切り捨て除算)の違いです。10 / 33.3333(float)、10 // 33(int)になります。消費税計算のように正確な整数結果が欲しい場面では//を使います。

もう1つの注意点はfloatの精度問題です:

print(0.1 + 0.2)  # 0.30000000000000004(!)

これはPython固有のバグではなく、IEEE 754浮動小数点規格に起因するコンピュータ全般の仕様です。金額計算のように正確さが求められる場面では、Python標準ライブラリのdecimalモジュールを使います。今の段階では「小数の計算には微小な誤差がある」ことを頭に入れておけば十分です。

文字列型 — テキストの操作

文字列(str)はシングルクォート'またはダブルクォート"で囲みます。どちらでも同じですが、PEP 8ではプロジェクト内で統一することを推奨しています。

greeting = "こんにちは"
name = '田中'
message = f"{greeting}、{name}さん"  # f-string(フォーマット文字列)
print(message)  # こんにちは、田中さん

f-string(f文字列)はPython 3.6で導入された機能で、文字列の中に{変数名}で値を埋め込めます。旧い書き方(%演算子や.format())もありますが、f-stringが最も読みやすく現代的です。

文字列でよく使う操作を一覧にまとめます:

操作 コード 結果
結合 "Hello" + " World" "Hello World"
繰り返し "Ha" * 3 "HaHaHa"
長さ len("Python") 6
大文字化 "hello".upper() "HELLO"
置換 "cat".replace("c", "b") "bat"
分割 "a,b,c".split(",") ["a", "b", "c"]
含まれるか "Py" in "Python" True

文字列はイミュータブル(変更不可)です。name[0] = "K"のように一部を直接書き換えることはできません。変更が必要な場合は、新しい文字列を作成します。

リスト型 — 複数のデータをまとめる

リスト(list)は複数のデータを順番に格納するデータ型です。角括弧[]で作成します。

fruits = ["りんご", "バナナ", "みかん"]
scores = [85, 92, 78, 96, 88]
mixed = [1, "hello", 3.14, True]  # 異なる型も混在可能

リストの要素にはインデックス(番号)でアクセスします。重要なのは、番号は0から始まるということです:

fruits = ["りんご", "バナナ", "みかん"]
print(fruits[0])   # りんご(最初の要素)
print(fruits[1])   # バナナ(2番目の要素)
print(fruits[-1])  # みかん(最後の要素)

「なぜ0から?」と疑問に思うのは当然です。これはC言語から受け継いだ慣例で、メモリ上のアドレス計算に由来します。最初は違和感がありますが、すぐに慣れます。

リストの主要な操作:

fruits = ["りんご", "バナナ", "みかん"]

# 追加
fruits.append("ぶどう")        # 末尾に追加 → ["りんご", "バナナ", "みかん", "ぶどう"]

# 挿入
fruits.insert(1, "いちご")     # index 1に挿入

# 削除
fruits.remove("バナナ")        # 値を指定して削除
del fruits[0]                  # indexを指定して削除

# 長さ
print(len(fruits))             # 要素数

# ソート
scores = [85, 92, 78, 96]
scores.sort()                  # 昇順: [78, 85, 92, 96]
scores.sort(reverse=True)      # 降順: [96, 92, 85, 78]

# スライス(部分取得)
numbers = [0, 1, 2, 3, 4, 5]
print(numbers[1:4])            # [1, 2, 3](index 1〜3)
print(numbers[:3])             # [0, 1, 2](最初から3つ)
print(numbers[3:])             # [3, 4, 5](index 3以降)

スライスは最初は複雑に見えますが、データ分析でCSVの特定列を取り出す場面などで頻繁に使います。

型変換 — データ型を切り替える

プログラムを書いていると、型を変換する場面が頻繁にあります。

# 文字列 → 数値
age_str = "25"
age_int = int(age_str)     # 25(整数)
price = float("19.99")     # 19.99(小数)

# 数値 → 文字列
count = 42
message = "答えは" + str(count) + "です"

# ユーザー入力(input()は常に文字列を返す)
user_input = input("年齢を入力: ")  # "25"(文字列)
age = int(user_input)                # 25(整数に変換)

型変換でよくあるエラーは、数値に変換できない文字列をint()に渡すケースです。int("abc")ValueErrorになります。第9回のエラーハンドリングで対処法を学びます。

実践ワーク: BMI計算プログラム

学んだ知識を使って、BMI(Body Mass Index)計算プログラムを作りましょう。新しいファイル bmi.py を作成してください:

# BMI計算プログラム
print("=== BMI計算プログラム ===")

# ユーザーからの入力
height_cm = float(input("身長をcmで入力してください: "))
weight_kg = float(input("体重をkgで入力してください: "))

# BMI計算(体重kg ÷ 身長mの2乗)
height_m = height_cm / 100
bmi = weight_kg / (height_m ** 2)

# 結果表示
print(f"\n身長: {height_cm}cm")
print(f"体重: {weight_kg}kg")
print(f"BMI: {bmi:.1f}")  # 小数第1位まで表示

{bmi:.1f}.1f は「小数第1位まで表示」という書式指定です。:.2fなら小数第2位まで。これもf-stringの機能の1つです。

このプログラムには、ここまで学んだ要素がすべて含まれています:変数への代入、数値計算(/, **)、型変換(float())、f-string。動かしてみて、自分の値で確認してください。

まとめと次回の準備

今回のポイント: - 変数は「名前のついた箱」。=で値を代入する - 数値型(int/float)、文字列型(str)、リスト型(list)が基本の3型 - f-stringで文字列に値を埋め込める - リストのインデックスは0から始まる - int(), float(), str()で型変換

次回: 条件分岐(if文)を学びます。BMIプログラムに「正常体重か肥満か」の判定を追加するなど、プログラムに「判断」をさせる方法を身につけます。

参考文献: - Python公式チュートリアル「データ構造」(https://docs.python.org/ja/3/tutorial/datastructures.html) - PEP 8 — Style Guide for Python Code(https://peps.python.org/pep-0008/) - 『Fluent Python 第2版』Luciano Ramalho(オライリー・ジャパン、2022年)

Lecture 4条件分岐 — if文で判断するプログラムを作る

10:00

条件分岐 — if文で判断するプログラムを作る

プログラムに「判断」をさせる

ここまでのプログラムは、上から下へ一直線に実行されるだけでした。しかし現実の処理には「条件によって動作を変える」場面が必ずあります。

  • 年齢が18歳以上なら「成人」、未満なら「未成年」と表示する
  • パスワードが正しければログイン成功、間違っていればエラーを出す
  • テストの点数に応じてA〜Fの成績をつける

これを実現するのが条件分岐(if文)です。Pythonではif、elif、elseの3つのキーワードで記述します。

if文の基本構文

age = 20

if age >= 18:
    print("あなたは成人です")

この2行には、Pythonの文法で最も重要な2つの要素が含まれています:

1. コロン(:) — if文の条件の末尾に必ず書く 2. インデント(字下げ) — 条件が成立した時に実行するブロックを、スペース4つで字下げする

他の多くの言語(Java、C、JavaScript)ではブロックを{}で囲みますが、Pythonはインデントでブロックを表現します。これがPythonの最大の特徴の1つで、「The Zen of Python」の「Readability counts」を体現しています。

# Java(参考)
if (age >= 18) {
    System.out.println("成人です");
}

# Python — 括弧も波括弧も不要
if age >= 18:
    print("成人です")

if-else と if-elif-else

条件が成立しなかった場合の処理はelseで書きます:

temperature = 35

if temperature >= 35:
    print("猛暑日です。外出を控えましょう")
else:
    print("猛暑日ではありません")

3つ以上の条件分岐にはelif(else ifの略)を使います:

score = 78

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
elif score >= 60:
    grade = "D"
else:
    grade = "F"

print(f"あなたの成績は {grade} です")

elifの評価は上から順番に行われ、最初に成立した条件のブロックだけが実行されます。この例ではscore = 78なので、score >= 90はFalse、score >= 80もFalse、score >= 70がTrueとなり、grade = "C"が実行されます。残りの条件は評価されません。

比較演算子と論理演算子

条件文で使う演算子を一覧にまとめます:

比較演算子

演算子 意味
== 等しい x == 10
!= 等しくない x != 0
> より大きい x > 5
< より小さい x < 100
>= 以上 x >= 18
<= 以下 x <= 60

最重要: =(代入)と ==(比較)を間違えるのは、全プログラミング言語共通の初心者ミスです。if x = 10:と書くとエラーになります。Pythonではこの書き方をSyntaxErrorで弾いてくれますが、他の言語ではバグの原因になることがあります。

論理演算子

複数の条件を組み合わせるにはandornotを使います:

age = 25
income = 300  # 万円

# 両方の条件が必要(AND)
if age >= 20 and income >= 200:
    print("クレジットカード審査:通過の可能性あり")

# どちらか一方でOK(OR)
if age < 18 or age >= 65:
    print("割引対象です")

# 否定(NOT)
is_holiday = False
if not is_holiday:
    print("今日は平日です")

条件のネスト(入れ子)とフラット化

条件分岐を入れ子にすることは可能ですが、深くなると読みにくくなります:

# ❌ 深いネスト — 読みにくい
if user_exists:
    if password_correct:
        if not is_banned:
            print("ログイン成功")
        else:
            print("アカウント停止中")
    else:
        print("パスワードが違います")
else:
    print("ユーザーが見つかりません")

Martin Fowlerの著書『リファクタリング』で紹介されているガード節(Guard Clause)パターンを使うと、フラットで読みやすくなります:

# ✅ ガード節 — 異常系を先に弾く
if not user_exists:
    print("ユーザーが見つかりません")
elif not password_correct:
    print("パスワードが違います")
elif is_banned:
    print("アカウント停止中")
else:
    print("ログイン成功")

ネストを浅く保つことは、可読性の高いコードを書くための重要な原則です。

真偽値(bool型)の理解

条件分岐を理解するには、Pythonが何を「True」「False」と判定するか知る必要があります。

# 以下はすべてFalse(偽)と評価される
False, None, 0, 0.0, "", [], {}, set()

# それ以外はすべてTrue(真)
True, 1, -1, "hello", [1, 2], {"key": "value"}

この仕様を利用すると、空チェックが簡潔に書けます:

items = []

# 冗長な書き方
if len(items) == 0:
    print("リストは空です")

# Pythonicな書き方
if not items:
    print("リストは空です")

実践ワーク: 前回のBMI計算に判定を追加

第3回で作った bmi.py を改良して、BMI値に基づく判定を追加しましょう。新しいファイル bmi_v2.py を作成してください:

# BMI計算+判定プログラム
print("=== BMI計算・判定プログラム ===")

height_cm = float(input("身長(cm): "))
weight_kg = float(input("体重(kg): "))

height_m = height_cm / 100
bmi = weight_kg / (height_m ** 2)

# WHO基準による判定
if bmi < 18.5:
    category = "低体重(やせ型)"
    advice = "栄養バランスの見直しを検討しましょう"
elif bmi < 25.0:
    category = "普通体重"
    advice = "現在の生活習慣を維持しましょう"
elif bmi < 30.0:
    category = "肥満(1度)"
    advice = "食事と運動の見直しを検討しましょう"
else:
    category = "肥満(2度以上)"
    advice = "医師への相談を推奨します"

print(f"\nBMI: {bmi:.1f}")
print(f"判定: {category}")
print(f"アドバイス: {advice}")

このプログラムのポイントは、elifの条件をbmi < 25.0と書いている点です。すでにbmi < 18.5がFalseだったからこのelifに来ているので、暗黙的にbmi >= 18.5が保証されています。つまり18.5 <= bmi < 25.0と同義です。この「elifの暗黙の前提条件」を理解しておくと、無駄な条件を書かずに済みます。

まとめと次回の準備

今回のポイント: - if/elif/elseで条件分岐。コロンとインデントが文法の核 - ==(比較)と=(代入)を混同しない - and/or/notで条件を組み合わせる - ネストは浅く。ガード節パターンで異常系を先に処理 - 空リスト、空文字列、0、NoneはFalse

次回: 繰り返し処理(for文・while文)を学びます。「100人分のデータを処理する」「条件を満たすまで繰り返す」など、プログラミングの真価が発揮される場面です。

参考文献: - Python公式チュートリアル「制御フロー」(https://docs.python.org/ja/3/tutorial/controlflow.html) - Martin Fowler『リファクタリング 第2版』(オーム社、2019年) - PEP 8 — Programming Recommendations(https://peps.python.org/pep-0008/#programming-recommendations)

Lecture 5繰り返し処理 — for文とwhile文をマスターする

12:00

繰り返し処理 — for文とwhile文をマスターする

「同じ作業を繰り返す」力

プログラミングが手作業に圧勝する場面があります。それが「繰り返し」です。1000人分のデータを処理する、1万行のファイルから特定の行を探す、100回の計算を瞬時に終わらせる — これらはすべて繰り返し処理で実現します。

手作業なら1時間かかる処理が、繰り返し文を使えば数秒で完了します。プログラミングの実用的な恩恵を最も実感できるのがこの回です。

for文 — 「決まった回数」の繰り返し

for文は、リストやrangeの要素を1つずつ取り出して処理します。

# リストの各要素を処理
fruits = ["りんご", "バナナ", "みかん"]
for fruit in fruits:
    print(f"{fruit}が好きです")

出力:

りんごが好きです
バナナが好きです
みかんが好きです

ここでfruitは「ループ変数」と呼ばれ、繰り返しのたびにリストの次の要素が自動的に代入されます。変数名は何でも構いませんが、リストがfruits(複数形)ならループ変数はfruit(単数形)とするのが慣例です。

range() — 数値の連番を生成する

特定の回数だけ繰り返したい場合はrange()を使います:

# 0, 1, 2, 3, 4 を繰り返す
for i in range(5):
    print(i)

# 1から10まで
for i in range(1, 11):  # 11は含まれない
    print(i)

# 2ずつ増やす(0, 2, 4, 6, 8)
for i in range(0, 10, 2):
    print(i)

range(1, 11)が「1から10まで」になる理由は、Pythonの一貫した設計思想によるものです。スライスlist[1:11]と同様に、終了値は含みません。数学の半開区間 [1, 11) に対応しており、range(n)の要素数がちょうどn個になるという利点があります。オランダの計算機科学者エドガー・ダイクストラが1982年の論文「Why Numbering Should Start at Zero」でこの設計の合理性を論じています。

enumerate() — インデックスと値を同時に取得

要素だけでなく「何番目か」も必要な場面では、enumerate()を使います:

members = ["田中", "鈴木", "佐藤", "高橋"]
for i, name in enumerate(members, start=1):
    print(f"{i}. {name}")

出力:

1. 田中
2. 鈴木
3. 佐藤
4. 高橋

start=1を指定すると番号が1から始まります。これを使わずにfor i in range(len(members)):と書くのは冗長で、Pythonではアンチパターンとされています。

while文 — 「条件が成立する間」繰り返す

for文が「決まった回数」の繰り返しなら、while文は「条件を満たす間ずっと」繰り返す構文です。

count = 0
while count < 5:
    print(f"カウント: {count}")
    count += 1  # countを1増やす。これを忘れると無限ループ!

while文で最も危険なのが無限ループです。条件が永遠にTrueのままだと、プログラムが停止しません。count += 1を書き忘れると、countはずっと0のままなのでcount < 5が永遠にTrueです。

万が一無限ループにハマったら、ターミナルでCtrl + Cを押すと強制終了できます。

while文の実用的な使い方 — ユーザー入力の検証

while文の真価は「正しい入力が来るまで繰り返す」パターンで発揮されます:

while True:
    age_str = input("年齢を入力してください(0-120): ")
    if age_str.isdigit():
        age = int(age_str)
        if 0 <= age <= 120:
            break  # 正しい入力なのでループを抜ける
    print("無効な入力です。もう一度お願いします。")

print(f"入力された年齢: {age}")

while True:は意図的な無限ループで、内部のbreakで脱出します。このパターンは入力検証の定番で、実務でも頻繁に使います。

break、continue、else — ループ制御

break — ループを途中で抜ける

# 特定の値を見つけたら即終了
numbers = [4, 7, 2, 9, 1, 5, 8]
target = 9

for num in numbers:
    if num == target:
        print(f"{target}を見つけました!")
        break

continue — 残りの処理をスキップして次の繰り返しへ

# 偶数だけを表示(奇数はスキップ)
for i in range(10):
    if i % 2 != 0:
        continue  # 奇数ならスキップ
    print(i)  # 0, 2, 4, 6, 8

for-else — 「breakされなかった場合」の処理

Pythonにはfor文にelseを付ける独自の構文があります。breakが実行されなかった場合にelseブロックが実行されます:

# 素数判定
num = 17
for i in range(2, num):
    if num % i == 0:
        print(f"{num}は{i}で割り切れるので素数ではない")
        break
else:
    # breakされなかった = 割り切れる数がなかった
    print(f"{num}は素数です")

この構文はPython特有で、他の言語には存在しません。初見では混乱しますが、「見つからなかった場合」の処理を簡潔に書けるため、便利な場面があります。

リスト内包表記 — Pythonicなループ

リストを生成するためだけのforループは、リスト内包表記で1行にまとめられます:

# 通常のforループ
squares = []
for i in range(10):
    squares.append(i ** 2)

# リスト内包表記(同じ結果)
squares = [i ** 2 for i in range(10)]
# → [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 条件付き(偶数の2乗だけ)
even_squares = [i ** 2 for i in range(10) if i % 2 == 0]
# → [0, 4, 16, 36, 64]

リスト内包表記はPython公式ドキュメントでも推奨されている書き方で、通常のforループより高速に動作します。ただし複雑な処理を詰め込みすぎると逆に読みにくくなるため、「1行で理解できる範囲」に留めるのがベストプラクティスです。

実践ワーク: 九九表を作る

# 九九表の作成
print("=== 九九表 ===")
print("    ", end="")
for j in range(1, 10):
    print(f"{j:4d}", end="")
print()
print("-" * 40)

for i in range(1, 10):
    print(f"{i} | ", end="")
    for j in range(1, 10):
        print(f"{i*j:4d}", end="")
    print()

これは二重ループ(ループの中にループ)の例です。外側のforが「行」、内側のforが「列」を担当します。end=""printの末尾の改行を抑制するオプションです。{i*j:4d}は「4桁の整数として表示」という書式指定。

このプログラムを実行して九九表が正しく表示されることを確認したら、さらに挑戦:range(1, 10)range(1, 20)に変えると19×19の表になります。

まとめと次回の準備

今回のポイント: - forは決まった回数の繰り返し、whileは条件ベースの繰り返し - range()で連番生成、enumerate()でインデックス付きループ - breakでループ脱出、continueでスキップ - while文の無限ループに注意(Ctrl+Cで強制終了) - リスト内包表記はPythonicだが、読みやすさ優先

次回: 関数を学びます。ここまでのコードは処理が1つのファイルに並んでいましたが、関数を使うことで「再利用可能な部品」としてコードを整理できるようになります。

参考文献: - Python公式チュートリアル「その他の制御フローツール」(https://docs.python.org/ja/3/tutorial/controlflow.html) - Dijkstra, E.W. "Why Numbering Should Start at Zero" (1982), EWD831 - 『Effective Python 第2版』Brett Slatkin(オライリー・ジャパン、2020年)Item 7: リスト内包表記

Lecture 6関数 — コードを整理して再利用する技術

12:00

関数 — コードを整理して再利用する技術

なぜ関数が必要なのか

ここまでの講義で、変数、条件分岐、繰り返しを学びました。これだけでもプログラムは書けますが、コードが長くなると問題が生じます。

例えば、BMI計算を3人分行うプログラムを想像してください。関数を使わない場合、同じ計算コードを3回コピー&ペーストすることになります。そして計算式を修正したくなったら、3箇所すべてを直さなければなりません。ソフトウェア工学でこれはDRY原則(Don't Repeat Yourself)の違反と呼ばれ、Andy HuntとDave Thomasの古典的名著『達人プログラマー』で強く戒められています。

関数は「処理に名前をつけて、何度でも呼び出せるようにする仕組み」です。

関数の基本構文

def greet(name):
    """挨拶メッセージを表示する"""
    print(f"こんにちは、{name}さん!")

# 関数の呼び出し
greet("田中")   # こんにちは、田中さん!
greet("鈴木")   # こんにちは、鈴木さん!

構成要素を分解します:

要素 説明
def def greet 関数定義のキーワード
関数名 greet 動詞で始めるのが慣例(calculate_bmi, get_user
引数 (name) 関数に渡すデータ。複数可
docstring """挨拶を表示""" 関数の説明。省略可だが書くのが良い習慣
本体 print(...) インデントされた処理ブロック

戻り値(return)— 結果を返す

print()で表示するだけでなく、計算結果を呼び出し元に返したい場合はreturnを使います:

def calculate_bmi(height_cm, weight_kg):
    """BMIを計算して返す"""
    height_m = height_cm / 100
    bmi = weight_kg / (height_m ** 2)
    return round(bmi, 1)

# 戻り値を変数に格納
my_bmi = calculate_bmi(170, 65)
print(f"BMI: {my_bmi}")  # BMI: 22.5

# 直接使うことも可能
if calculate_bmi(160, 80) >= 25:
    print("肥満判定です")

returnがない関数は、暗黙的にNoneを返します。表示が目的の関数(greet()など)はreturn不要ですが、計算が目的の関数は必ずreturnで結果を返すべきです。これにより、関数の「仕事」が明確になります。

重要な違い: print()は画面に表示するだけで、値を返しません。returnは値を返すだけで、画面に表示しません。初心者の多くがこの2つを混同します。

引数の種類 — 柔軟な関数設計

デフォルト引数

引数に初期値を設定できます。呼び出し時に省略された場合、デフォルト値が使われます:

def greet(name, greeting="こんにちは"):
    print(f"{greeting}、{name}さん!")

greet("田中")                    # こんにちは、田中さん!
greet("鈴木", "おはようございます")  # おはようございます、鈴木さん!

キーワード引数

引数名を明示して渡すと、順番を自由に変えられます:

def create_user(name, age, city):
    print(f"{name} ({age}歳, {city})")

# 位置引数(順番が重要)
create_user("田中", 30, "東京")

# キーワード引数(順番自由)
create_user(city="大阪", name="鈴木", age=25)

キーワード引数は、引数が3つ以上ある関数で特に有効です。呼び出し側のコードが自己文書化され、何を渡しているか一目でわかります。

可変長引数(args, *kwargs)

引数の数が事前にわからない場合に使う上級テクニックです:

def total(*numbers):
    """任意個の数値を受け取って合計を返す"""
    return sum(numbers)

print(total(1, 2, 3))        # 6
print(total(10, 20, 30, 40)) # 100

*argsはタプル(変更不可のリスト)として受け取り、**kwargsは辞書として受け取ります。Pythonの標準ライブラリでもprint(*objects)のように多用されています。

スコープ — 変数の「見える範囲」

関数の内部で作った変数は、関数の外からは見えません。これをローカルスコープと言います:

def calculate():
    result = 100  # ローカル変数
    return result

calculate()
print(result)  # NameError! — resultは関数の外では存在しない

逆に、関数の外で定義した変数(グローバル変数)は関数内から読めますが、書き換えはできません:

tax_rate = 0.10  # グローバル変数

def calculate_tax(price):
    return price * tax_rate  # 読み取りはOK

print(calculate_tax(1000))  # 100.0

グローバル変数の値を関数内で変更したい場合はglobalキーワードを使いますが、これはバグの温床になるため原則として使わないのがベストプラクティスです。関数は引数で受け取り、returnで返す — この「入口と出口を明確にする」設計が、保守しやすいコードの基本です。

関数設計の原則

良い関数を書くためのガイドラインをまとめます:

原則 説明 悪い例 良い例
1つの仕事だけ 関数は1つのタスクに集中 calculate_and_print_bmi() calculate_bmi() + print_result()
動詞で命名 何をするか名前でわかる data() fetch_data()
短く保つ 目安20行以内 100行の巨大関数 小さな関数に分割
副作用を避ける 引数以外を変更しない グローバル変数を書き換え return で結果を返す

Robert C. Martinの著書『Clean Code』では「関数は1つのことを行い、それをうまく行い、それだけを行うべき」と述べられています。

実践ワーク: 成績管理プログラム

学んだ関数の知識を活かして、テスト成績を管理するプログラムを作りましょう:

def calculate_average(scores):
    """点数リストの平均を計算する"""
    if not scores:
        return 0
    return sum(scores) / len(scores)

def get_grade(average):
    """平均点からグレードを判定する"""
    if average >= 90:
        return "A"
    elif average >= 80:
        return "B"
    elif average >= 70:
        return "C"
    elif average >= 60:
        return "D"
    return "F"

def print_report(name, scores):
    """成績レポートを表示する"""
    avg = calculate_average(scores)
    grade = get_grade(avg)
    print(f"\n--- {name}の成績レポート ---")
    print(f"科目数: {len(scores)}")
    print(f"合計: {sum(scores)}点")
    print(f"平均: {avg:.1f}点")
    print(f"最高: {max(scores)}点 / 最低: {min(scores)}点")
    print(f"総合評価: {grade}")

# 使用例
print_report("田中太郎", [85, 92, 78, 96, 88])
print_report("鈴木花子", [72, 65, 81, 59, 77])

calculate_average()get_grade()print_report()の3つの関数がそれぞれ1つの役割を担っています。print_report()が他の2つを呼び出す構造は、関数の組み合わせ(合成)の典型例です。

まとめと次回の準備

今回のポイント: - defで関数を定義、returnで値を返す - print()returnは別物 - デフォルト引数、キーワード引数で柔軟な設計 - ローカルスコープ: 関数内の変数は外から見えない - 1関数1仕事、動詞で命名、短く保つ

次回: 辞書(dict)とセット(set)を学びます。リストが「順番でデータを管理」するのに対し、辞書は「名前(キー)でデータを管理」する仕組みです。ユーザー情報や設定値の管理に不可欠なデータ型です。

参考文献: - Hunt, Thomas『達人プログラマー 第2版』(オーム社、2020年) - Martin, Robert C.『Clean Code』(KADOKAWA、2017年) - Python公式チュートリアル「関数定義」(https://docs.python.org/ja/3/tutorial/controlflow.html#defining-functions)

Lecture 7辞書とセット — データを効率的に管理する

10:00

辞書とセット — データを効率的に管理する

リストの限界と辞書の登場

前回までリストを使ってデータを管理してきましたが、リストには弱点があります。例えば生徒の成績を管理する場合:

names = ["田中", "鈴木", "佐藤"]
scores = [85, 92, 78]

「鈴木さんの点数は?」と聞かれたとき、まずnamesから鈴木のインデックス(1)を探し、そのインデックスでscores[1]を参照する — 面倒で、エラーの元です。2つのリストの整合性を手動で管理するのは現実的ではありません。

辞書(dict) は「キーと値のペア」でデータを管理するデータ型で、まさにこの問題を解決します。

辞書の基本

scores = {
    "田中": 85,
    "鈴木": 92,
    "佐藤": 78
}

# 値の取得
print(scores["鈴木"])  # 92

# 値の更新
scores["田中"] = 90

# 新しいキーの追加
scores["高橋"] = 88

# キーの存在確認
if "鈴木" in scores:
    print(f"鈴木: {scores['鈴木']}点")

辞書のキーには文字列、数値、タプルが使えます(リストは使えません — イミュータブルなオブジェクトのみ可)。値には何でも入れられます。

リスト vs 辞書の使い分け

特徴 リスト 辞書
アクセス方法 インデックス(数値) キー(名前)
順序 あり(Python 3.7以降は辞書も順序保持) あり
適した場面 順番が重要なデータ 名前で引きたいデータ
検索速度 O(n) — 遅い O(1) — 高速
[85, 92, 78] {"田中": 85, "鈴木": 92}

検索速度の差は重要です。リストから特定の値を探す場合、先頭から1つずつ確認するため、データが多いほど遅くなります(計算量O(n))。辞書はハッシュテーブルという内部構造を使っており、データ量に関わらずほぼ一定時間で検索できます(計算量O(1))。Pythonの辞書実装は非常に高速で、100万件のデータでもキー検索は一瞬です。

辞書の操作メソッド

user = {
    "name": "田中太郎",
    "age": 30,
    "city": "東京",
    "email": "tanaka@example.com"
}

# 安全な値の取得(キーが無くてもエラーにならない)
phone = user.get("phone", "未登録")  # "未登録"

# 全キー・全値・全ペアの取得
print(list(user.keys()))    # ["name", "age", "city", "email"]
print(list(user.values()))  # ["田中太郎", 30, "東京", "tanaka@example.com"]
print(list(user.items()))   # [("name", "田中太郎"), ("age", 30), ...]

# 削除
del user["email"]           # キーを指定して削除
removed = user.pop("city")  # 削除して値を返す("東京")

# 辞書の結合(Python 3.9以降)
defaults = {"theme": "dark", "lang": "ja"}
custom = {"theme": "light"}
settings = defaults | custom  # {"theme": "light", "lang": "ja"}

user["phone"]は存在しないキーだとKeyError例外が発生しますが、user.get("phone", "未登録")ならエラーにならずデフォルト値を返します。実務では.get()を使う場面が多いです。

辞書のループ

scores = {"田中": 85, "鈴木": 92, "佐藤": 78}

# キーでループ
for name in scores:
    print(name)

# キーと値を同時に取得(最も実用的)
for name, score in scores.items():
    print(f"{name}: {score}点")

# 値だけでループ
total = sum(scores.values())
average = total / len(scores)
print(f"平均点: {average:.1f}")

辞書の入れ子 — 複雑なデータ構造

辞書の値に辞書やリストを入れることで、複雑なデータを表現できます。これはJSON(Web APIで広く使われるデータ形式)と同じ構造です:

students = {
    "田中": {
        "age": 20,
        "scores": [85, 92, 78],
        "club": "テニス部"
    },
    "鈴木": {
        "age": 21,
        "scores": [90, 88, 95],
        "club": "プログラミング部"
    }
}

# 鈴木の数学の点数(scoresの最初の要素)
print(students["鈴木"]["scores"][0])  # 90

# 全員の平均点を計算
for name, data in students.items():
    avg = sum(data["scores"]) / len(data["scores"])
    print(f"{name}: 平均 {avg:.1f}点")

Web開発やデータ分析では、APIから返ってくるJSONデータを辞書として扱う場面が頻繁にあります。この入れ子構造に慣れておくことは非常に重要です。

セット(集合)— 重複のないデータ

セット(set)は「重複を許さない」データ型です。数学の集合と同じ概念です:

# 重複が自動的に除去される
fruits = {"りんご", "バナナ", "みかん", "りんご"}
print(fruits)  # {"りんご", "バナナ", "みかん"}

# リストから重複を除去する定番テクニック
raw_data = [1, 2, 3, 2, 1, 4, 3, 5]
unique = list(set(raw_data))
print(unique)  # [1, 2, 3, 4, 5]

セットの真価は集合演算にあります:

python_users = {"田中", "鈴木", "佐藤", "高橋"}
java_users = {"鈴木", "高橋", "山田", "伊藤"}

# 両方使える人(積集合)
both = python_users & java_users
print(both)  # {"鈴木", "高橋"}

# どちらかを使える人(和集合)
either = python_users | java_users
print(either)  # {"田中", "鈴木", "佐藤", "高橋", "山田", "伊藤"}

# Pythonだけの人(差集合)
only_python = python_users - java_users
print(only_python)  # {"田中", "佐藤"}

データ分析で「A群とB群の共通要素」「AにあってBにない要素」を抽出する場面でセットは強力です。リストのfor文で同じことをやると数十行かかる処理が、セット演算なら1行で済みます。

実践ワーク: 簡易住所録

def create_contact(name, phone, email=""):
    """連絡先辞書を作成する"""
    return {"name": name, "phone": phone, "email": email}

def display_contacts(contacts):
    """連絡先一覧を表示する"""
    print(f"\n{'名前':<10} {'電話番号':<15} {'メール'}")
    print("-" * 45)
    for c in contacts:
        print(f"{c['name']:<10} {c['phone']:<15} {c.get('email', '-')}")

def search_contact(contacts, keyword):
    """名前で連絡先を検索する"""
    results = [c for c in contacts if keyword in c["name"]]
    return results

# データ作成
contacts = [
    create_contact("田中太郎", "090-1234-5678", "tanaka@example.com"),
    create_contact("鈴木花子", "080-9876-5432", "suzuki@example.com"),
    create_contact("佐藤次郎", "070-1111-2222"),
]

# 一覧表示
display_contacts(contacts)

# 検索
found = search_contact(contacts, "田中")
if found:
    print(f"\n検索結果: {found[0]['name']} - {found[0]['phone']}")

この演習では、辞書のリスト([{}, {}, {}])という実務で頻出の構造を使っています。第10回の総合演習ではこれを拡張して、ファイル保存機能を追加します。

まとめと次回の準備

今回のポイント: - 辞書はキーと値のペア。名前でデータを引ける - .get()で安全にアクセス、.items()でループ - 辞書の入れ子でJSON的な複雑データを表現 - セットは重複除去と集合演算に使う - 辞書のキー検索はO(1)で高速

次回: ファイル操作を学びます。CSVファイルやテキストファイルの読み書きを行い、プログラムの処理結果を永続的に保存する方法を身につけます。

参考文献: - Python公式チュートリアル「データ構造」(https://docs.python.org/ja/3/tutorial/datastructures.html#dictionaries) - 『Effective Python 第2版』Brett Slatkin(オライリー・ジャパン、2020年)Item 15: 辞書の欠損キーの処理 - Raymond Hettinger "Modern Python Dictionaries" (PyCon 2017)

Lecture 8ファイル操作 — CSVやテキストファイルの読み書き

12:00

ファイル操作 — CSVやテキストファイルの読み書き

プログラムの結果を「残す」

ここまでのプログラムは、実行するたびに結果が消えていました。変数に入れたデータはプログラム終了と同時に失われます。ファイル操作を学ぶと、データを永続的に保存し、次回の実行時に読み込むことが可能になります。

業務自動化の観点でも、ファイル操作は最も実用的なスキルの1つです。「Excelの売上データを読み込んで集計する」「ログファイルからエラーを抽出する」「処理結果をCSVに書き出す」— これらはすべてファイル操作の応用です。

テキストファイルの読み書き

ファイルへの書き込み

# ファイルを開いて書き込む
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("1行目のテキスト\n")
    f.write("2行目のテキスト\n")
    f.write("3行目のテキスト\n")

この構文の各要素を解説します:

要素 説明
with ファイルを自動的に閉じる構文(推奨)
open() ファイルを開く組み込み関数
"output.txt" ファイルパス
"w" 書き込みモード(write)。既存内容は上書きされる
encoding="utf-8" 文字コード指定。日本語を扱うなら必須
as f ファイルオブジェクトにfという名前をつける

with文を使う理由: ファイルは開いたら必ず閉じる必要があります。withを使わない場合、f.close()を手動で呼ぶ必要があり、例外が発生すると閉じ忘れる危険があります。withはブロックを抜ける際に自動的にファイルを閉じるため、安全です。Python公式ドキュメントでもwithの使用が推奨されています。

ファイルモード一覧

モード 意味 既存ファイル ファイルが無い場合
"r" 読み取り(デフォルト) 読み取り FileNotFoundError
"w" 書き込み 上書き 新規作成
"a" 追記 末尾に追加 新規作成
"x" 排他的作成 FileExistsError 新規作成

"w"は既存の内容を完全に消す点に注意してください。既存データを残したまま追加したい場合は"a"(append)を使います。

ファイルの読み込み

# 全体を一度に読み込む
with open("output.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)

# 1行ずつ読み込む(大きなファイルに有効)
with open("output.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line.strip())  # strip()で末尾の改行を除去

# 全行をリストとして読み込む
with open("output.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()
    print(f"合計 {len(lines)} 行")

大きなファイル(数GB以上)を扱う場合、f.read()で全体を読むとメモリ不足になります。for line in f:で1行ずつ処理するのがメモリ効率の良い方法です。

CSV(カンマ区切りデータ)の操作

CSVはExcelやGoogle Sheetsで広く使われるデータ形式です。Python標準ライブラリのcsvモジュールで簡単に扱えます。

CSVの書き込み

import csv

students = [
    ["名前", "数学", "英語", "理科"],
    ["田中", 85, 92, 78],
    ["鈴木", 90, 88, 95],
    ["佐藤", 72, 65, 81],
]

with open("scores.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(students)

newline=""は、Windowsで余分な空行が入るのを防ぐおまじないです。Python公式ドキュメントで明記されている推奨設定ですので、CSVを書く時は常につけてください。

CSVの読み込み

import csv

with open("scores.csv", "r", encoding="utf-8") as f:
    reader = csv.reader(f)
    header = next(reader)  # 1行目(ヘッダー)を取得

    print(f"科目: {header[1:]}")
    for row in reader:
        name = row[0]
        scores = [int(s) for s in row[1:]]
        avg = sum(scores) / len(scores)
        print(f"{name}: 平均 {avg:.1f}点")

DictReader — 辞書として読み込む

ヘッダー付きCSVはDictReaderで辞書として読むと、インデックスではなくカラム名でアクセスでき、コードが読みやすくなります:

import csv

with open("scores.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    for row in reader:
        name = row["名前"]
        math = int(row["数学"])
        print(f"{name}: 数学 {math}点")

pathlib — モダンなパス操作

Python 3.4で導入されたpathlibモジュールは、ファイルパスをオブジェクトとして扱えます。従来のos.pathより直感的で、Python公式もpathlibの使用を推奨しています:

from pathlib import Path

# パスの作成
data_dir = Path("data")
file_path = data_dir / "scores.csv"  # / 演算子でパス結合

# ディレクトリ作成(存在してもエラーにならない)
data_dir.mkdir(exist_ok=True)

# ファイルの存在確認
if file_path.exists():
    print(f"{file_path} は存在します")
    print(f"サイズ: {file_path.stat().st_size} バイト")

# テキストの読み書き(with不要のショートカット)
file_path.write_text("Hello, pathlib!", encoding="utf-8")
content = file_path.read_text(encoding="utf-8")

# ディレクトリ内のファイル一覧
for p in Path(".").glob("*.py"):
    print(p.name)

Pathオブジェクトの/演算子によるパス結合は、OS間の差異(Windowsの\とMac/Linuxの/)を自動的に吸収してくれます。

実践ワーク: 家計簿プログラム

CSVファイルで家計簿データを管理するプログラムを作りましょう:

import csv
from pathlib import Path
from datetime import date

FILEPATH = Path("household.csv")

def init_file():
    """CSVファイルが無ければヘッダー付きで作成"""
    if not FILEPATH.exists():
        with open(FILEPATH, "w", encoding="utf-8", newline="") as f:
            writer = csv.writer(f)
            writer.writerow(["日付", "カテゴリ", "品名", "金額"])

def add_expense(category, item, amount):
    """支出を1件追加する"""
    with open(FILEPATH, "a", encoding="utf-8", newline="") as f:
        writer = csv.writer(f)
        writer.writerow([date.today(), category, item, amount])
    print(f"追加: {category} / {item} / {amount}円")

def show_summary():
    """カテゴリ別の合計を表示する"""
    totals = {}
    with open(FILEPATH, "r", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        for row in reader:
            cat = row["カテゴリ"]
            amt = int(row["金額"])
            totals[cat] = totals.get(cat, 0) + amt

    print("\n--- カテゴリ別支出 ---")
    grand_total = 0
    for cat, total in sorted(totals.items()):
        print(f"  {cat}: {total:,}円")
        grand_total += total
    print(f"  合計: {grand_total:,}円")

# 使用例
init_file()
add_expense("食費", "スーパー", 3500)
add_expense("交通費", "電車定期", 12000)
add_expense("食費", "コンビニ", 680)
show_summary()

このプログラムは、ファイル操作(opencsv)、関数、辞書、f-stringの書式指定({:,}でカンマ区切り)など、これまで学んだ要素の集大成です。

まとめと次回の準備

今回のポイント: - with open()でファイルを安全に開閉する - "w"は上書き、"a"は追記、"r"は読み取り - CSV操作にはcsvモジュール。DictReaderが便利 - pathlib.Pathでモダンなパス操作 - 日本語ファイルはencoding="utf-8"を忘れずに

次回: エラーハンドリングを学びます。「ファイルが存在しない」「入力値が不正」「ネットワーク切断」— プログラムは様々なエラーに遭遇します。try/exceptでエラーを適切に処理する技術を身につけます。

参考文献: - Python公式ドキュメント「csvモジュール」(https://docs.python.org/ja/3/library/csv.html) - Python公式ドキュメント「pathlib」(https://docs.python.org/ja/3/library/pathlib.html) - 『退屈なことはPythonにやらせよう 第2版』Al Sweigart(オライリー・ジャパン、2023年)第9章

Lecture 9エラーハンドリングとデバッグ — バグとの付き合い方

10:00

エラーハンドリングとデバッグ — バグとの付き合い方

エラーは敵ではなくガイドである

プログラミングをしていると、エラーメッセージは日常的に目にします。プロのエンジニアでも1日に何十回とエラーに遭遇します。重要なのは「エラーを出さないこと」ではなく「エラーメッセージを正しく読んで、素早く原因を特定すること」です。

Pythonのエラーメッセージは他の言語と比べて非常に親切です。Python 3.10以降ではエラーメッセージがさらに改善され、「ここが間違っているのでは?」と具体的な修正案まで示してくれるようになりました。

Pythonの2種類のエラー

1. SyntaxError(構文エラー)

コードの書き方自体が間違っている場合に発生します。プログラムは1行も実行されません:

# コロン忘れ
if True
    print("hello")
# SyntaxError: expected ':'

# 括弧の閉じ忘れ
print("hello"
# SyntaxError: '(' was never closed

# 全角スペース(日本語環境で頻発)
name = "太郎"
 print(name)  # ← 全角スペースでインデント
# SyntaxError: invalid character ' ' (U+3000)

SyntaxErrorはエラーメッセージに行番号と位置^マーク)が表示されるので、比較的見つけやすいエラーです。

2. 例外(Exception)— 実行時エラー

構文は正しいが、実行中に問題が発生した場合に起きます:

例外 原因
NameError 未定義の変数を使用 print(undefined_var)
TypeError 型の不一致 "hello" + 5
ValueError 値が不正 int("abc")
IndexError リストの範囲外 [1,2,3][10]
KeyError 辞書にキーが無い {"a": 1}["b"]
FileNotFoundError ファイルが無い open("nofile.txt")
ZeroDivisionError ゼロ除算 10 / 0

try/except — 例外を捕まえる

例外が発生してもプログラムを停止させず、適切に処理する仕組みがtry/exceptです:

try:
    age = int(input("年齢を入力: "))
    print(f"来年は{age + 1}歳です")
except ValueError:
    print("数値を入力してください")

tryブロック内のコードで例外が発生すると、残りのtryブロックはスキップされ、該当するexceptブロックが実行されます。

複数の例外を処理する

def safe_divide(a, b):
    try:
        result = a / b
    except ZeroDivisionError:
        print("エラー: 0で割ることはできません")
        return None
    except TypeError:
        print("エラー: 数値を入力してください")
        return None
    else:
        # 例外が発生しなかった場合のみ実行
        print(f"計算成功: {a} / {b} = {result}")
        return result
    finally:
        # 例外の有無に関わらず必ず実行
        print("--- 計算処理終了 ---")

safe_divide(10, 3)   # 計算成功: 10 / 3 = 3.3333...
safe_divide(10, 0)   # エラー: 0で割ることはできません
safe_divide("a", 3)  # エラー: 数値を入力してください
ブロック 実行タイミング
try まず試みる処理
except 例外が発生した場合
else 例外が発生しなかった場合(省略可)
finally 例外の有無に関わらず必ず(省略可)

finallyは、ファイルのクローズやネットワーク接続の切断など、「何があっても必ず実行したい処理」に使います。ただしwith文を使えばfinallyが不要になるケースがほとんどです。

エラーハンドリングのベストプラクティス

1. 具体的な例外を捕まえる

# ❌ 全例外をキャッチ(バグを隠す危険)
try:
    do_something()
except Exception:
    pass  # 何もしない → バグが永遠に見つからない

# ✅ 具体的な例外を指定
try:
    value = int(user_input)
except ValueError:
    print("数値ではありません")

except Exceptionや素のexcept:は、プログラミングのバグ(NameErrorAttributeErrorなど)まで握りつぶしてしまうため、原則として使わないでください。捕まえるべき例外を明示するのが鉄則です。

2. EAFP原則 — 「許可より許しを求める」

Pythonのコーディングスタイルでは、「事前にチェックしてから実行する」(LBYL: Look Before You Leap)より「まず実行して、ダメなら例外を処理する」(EAFP: Easier to Ask Forgiveness than Permission)が推奨されています:

# LBYL(他言語的なスタイル)
if key in dictionary:
    value = dictionary[key]
else:
    value = default

# EAFP(Pythonicなスタイル)
try:
    value = dictionary[key]
except KeyError:
    value = default

# さらにPythonic(最善の方法)
value = dictionary.get(key, default)

この原則はPythonの公式用語集にも記載されている、Python文化の重要な要素です。

デバッグの技法

print()デバッグ

最もシンプルで効果的なデバッグ方法は、疑わしい箇所にprint()を入れて変数の値を確認することです:

def calculate_discount(price, rate):
    print(f"[DEBUG] price={price}, rate={rate}")  # デバッグ用
    discount = price * rate
    print(f"[DEBUG] discount={discount}")          # デバッグ用
    final = price - discount
    return final

デバッグが終わったらprint()を削除することを忘れないでください。本番コードにデバッグ用printが残るのはよくある事故です。

breakpoint() — 対話的デバッグ

Python 3.7で導入されたbreakpoint()は、プログラムの実行を一時停止して対話的にデバッグできます:

def process_data(items):
    for i, item in enumerate(items):
        result = item * 2
        if result > 10:
            breakpoint()  # ここで一時停止
        print(result)

実行すると(Pdb)プロンプトが表示され、変数の値を確認(p 変数名)したり、次の行に進む(n)ことができます。VS Codeのデバッグ機能を使えば、GUIでブレークポイントを設定してより快適にデバッグできます。

エラーメッセージの読み方

Pythonのトレースバック(エラーの経路表示)は下から上に読むのが基本です:

Traceback (most recent call last):
  File "main.py", line 10, in main        2. ここから呼ばれた
    result = calculate(data)
  File "main.py", line 5, in calculate    1. ここでエラーが発生
    return data[index]
IndexError: list index out of range       3. エラーの内容

まず最下行のエラーメッセージを読み、次にその直上の行番号を確認。これだけで9割のエラーは原因特定できます。

実践ワーク: 堅牢な入力処理

前回の家計簿プログラムに、エラーハンドリングを追加しましょう:

def get_valid_amount():
    """正しい金額が入力されるまで繰り返す"""
    while True:
        try:
            amount = int(input("金額(円): "))
            if amount <= 0:
                print("1円以上の金額を入力してください")
                continue
            return amount
        except ValueError:
            print("数値を入力してください(例: 1500)")

def load_csv_safe(filepath):
    """CSVファイルを安全に読み込む"""
    try:
        with open(filepath, "r", encoding="utf-8") as f:
            import csv
            return list(csv.DictReader(f))
    except FileNotFoundError:
        print(f"ファイルが見つかりません: {filepath}")
        return []
    except PermissionError:
        print(f"ファイルへのアクセス権限がありません: {filepath}")
        return []

# 使用例
amount = get_valid_amount()
print(f"入力された金額: {amount:,}円")

data = load_csv_safe("household.csv")
print(f"読み込んだレコード数: {len(data)}")

get_valid_amount()は「whileループ + try/except + 値の範囲チェック」を組み合わせた堅牢な入力関数です。このパターンは実務でも頻繁に使います。

まとめと次回の準備

今回のポイント: - SyntaxError(構文エラー)と例外(実行時エラー)は別物 - try/exceptで例外をキャッチ。具体的な例外名を指定 - except Exception:は原則禁止(バグを隠す) - EAFP原則: まず実行して、ダメなら例外処理 - エラーメッセージは下から読む

次回: 最終回の総合演習です。これまでの知識を総動員して、住所録管理アプリを完成させます。ファイル保存、検索、エラーハンドリングを統合した実用的なプログラムを作ります。

参考文献: - Python公式チュートリアル「エラーと例外」(https://docs.python.org/ja/3/tutorial/errors.html) - Python公式用語集「EAFP」(https://docs.python.org/ja/3/glossary.html#term-EAFP) - 『Effective Python 第2版』Brett Slatkin(オライリー・ジャパン、2020年)Item 65: try/except/else/finally

Lecture 10総合演習 — ミニプロジェクトで学びを定着させる

15:00

総合演習 — ミニプロジェクトで学びを定着させる

最終プロジェクト: 住所録管理アプリ

この講座の集大成として、これまで学んだすべての要素を組み合わせた「住所録管理アプリ」を作ります。完成すると、以下の機能を持つCLIアプリケーションが出来上がります:

  • 連絡先の追加・一覧表示・検索・削除
  • CSVファイルへの自動保存・読み込み
  • エラーハンドリングによる堅牢な入力処理

使用する知識の対応表:

知識 使う場面
変数・データ型 連絡先データの管理
条件分岐 メニュー選択、入力検証
繰り返し メインループ、検索処理
関数 各機能の部品化
辞書 連絡先1件のデータ構造
リスト 連絡先の集合
ファイル操作 CSV保存・読み込み
エラーハンドリング 入力エラー、ファイルエラー対応

Step 1: プロジェクト構造の設計

まず、プログラムの全体像を考えます。いきなりコードを書き始めるのではなく、「何が必要か」を先に整理するのがプロの仕事の進め方です。

address_book.py    メインプログラム1ファイルで完結
contacts.csv       データファイル自動生成

データ構造:1件の連絡先を辞書で表現します。

contact = {
    "name": "田中太郎",
    "phone": "090-1234-5678",
    "email": "tanaka@example.com",
    "address": "東京都渋谷区"
}

Step 2: ファイル操作部分

データの永続化を担う関数から作ります。プログラムの「土台」に当たる部分です:

import csv
from pathlib import Path

FILEPATH = Path("contacts.csv")
FIELDNAMES = ["name", "phone", "email", "address"]

def load_contacts():
    """CSVから連絡先を読み込む。ファイルが無ければ空リストを返す"""
    if not FILEPATH.exists():
        return []
    try:
        with open(FILEPATH, "r", encoding="utf-8") as f:
            reader = csv.DictReader(f)
            return list(reader)
    except (PermissionError, csv.Error) as e:
        print(f"読み込みエラー: {e}")
        return []

def save_contacts(contacts):
    """連絡先リストをCSVに保存する"""
    try:
        with open(FILEPATH, "w", encoding="utf-8", newline="") as f:
            writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
            writer.writeheader()
            writer.writerows(contacts)
    except PermissionError:
        print("エラー: ファイルに書き込めません。他のアプリで開いていませんか?")

csv.DictWriterは辞書のリストをCSVに書き出すクラスで、DictReaderと対になっています。fieldnamesでカラムの順序を指定します。

Step 3: CRUD操作の実装

CRUD(Create, Read, Update, Delete)はデータ管理の基本4操作です。Webアプリもデータベースも、突き詰めればこの4操作の組み合わせです:

def add_contact(contacts):
    """新しい連絡先を追加する"""
    print("\n--- 新規登録 ---")
    name = input("名前: ").strip()
    if not name:
        print("名前は必須です")
        return

    # 重複チェック
    if any(c["name"] == name for c in contacts):
        print(f"「{name}」は既に登録されています")
        return

    phone = input("電話番号: ").strip()
    email = input("メールアドレス(省略可): ").strip()
    address = input("住所(省略可): ").strip()

    contact = {
        "name": name,
        "phone": phone,
        "email": email,
        "address": address
    }
    contacts.append(contact)
    save_contacts(contacts)
    print(f"✓ {name}を登録しました")

def list_contacts(contacts):
    """連絡先一覧を表示する"""
    if not contacts:
        print("\n登録されている連絡先はありません")
        return

    print(f"\n--- 連絡先一覧({len(contacts)}件)---")
    print(f"{'#':<4} {'名前':<12} {'電話番号':<16} {'メール'}")
    print("-" * 56)
    for i, c in enumerate(contacts, start=1):
        email = c.get("email", "-") or "-"
        print(f"{i:<4} {c['name']:<12} {c['phone']:<16} {email}")

def search_contacts(contacts):
    """キーワードで連絡先を検索する"""
    keyword = input("\n検索キーワード: ").strip()
    if not keyword:
        return

    results = []
    for c in contacts:
        # 全フィールドを検索対象にする
        values = " ".join(c.values()).lower()
        if keyword.lower() in values:
            results.append(c)

    if results:
        print(f"\n{len(results)}件見つかりました:")
        for c in results:
            print(f"  {c['name']} - {c['phone']} - {c.get('email', '-')}")
    else:
        print(f"「{keyword}」に一致する連絡先はありません")

def delete_contact(contacts):
    """連絡先を削除する"""
    list_contacts(contacts)
    if not contacts:
        return

    try:
        num = int(input("\n削除する番号: "))
        if 1 <= num <= len(contacts):
            removed = contacts.pop(num - 1)
            save_contacts(contacts)
            print(f"✓ {removed['name']}を削除しました")
        else:
            print("無効な番号です")
    except ValueError:
        print("数値を入力してください")

各関数のポイント: - add_contact: .strip()で前後の空白を除去、any()で重複チェック - list_contacts: enumerate(start=1)で1始まりの番号付け、f-stringの:<12で左寄せ整形 - search_contacts: .lower()で大文字小文字を無視した検索、全フィールドを横断検索 - delete_contact: pop()でインデックス指定の削除、ValueError対策

Step 4: メインループ

アプリケーションの「心臓部」です。ユーザーの選択に応じて各機能を呼び出します:

def show_menu():
    """メニューを表示する"""
    print("\n=============================")
    print("  住所録管理アプリ")
    print("=============================")
    print("  1. 連絡先を追加")
    print("  2. 一覧表示")
    print("  3. 検索")
    print("  4. 削除")
    print("  0. 終了")
    print("=============================")

def main():
    """メインループ"""
    contacts = load_contacts()
    print(f"住所録を読み込みました({len(contacts)}件)")

    while True:
        show_menu()
        choice = input("操作を選択 [0-4]: ").strip()

        if choice == "1":
            add_contact(contacts)
        elif choice == "2":
            list_contacts(contacts)
        elif choice == "3":
            search_contacts(contacts)
        elif choice == "4":
            delete_contact(contacts)
        elif choice == "0":
            print("終了します。お疲れさまでした!")
            break
        else:
            print("0〜4の数字を入力してください")

if __name__ == "__main__":
    main()

if __name__ == "__main__":は、このファイルが直接実行された場合のみmain()を呼ぶPythonの慣用句です。他のファイルからimportされた場合は実行されません。チームでの開発やテストで重要になるパターンです。

Step 5: 完成版を動かす

上記のStep 1〜4のコードを1つのファイル address_book.py にまとめて実行してください。順序は: 1. import文 2. 定数(FILEPATH, FIELDNAMES) 3. ファイル操作関数(load_contacts, save_contacts) 4. CRUD関数 5. show_menu, main 6. if __name__ == "__main__"

ターミナルで python address_book.py を実行すると、対話的なメニューが表示されます。連絡先を何件か追加した後、contacts.csvをExcelやテキストエディタで開いて中身を確認してみてください。

発展課題(オプション)

基本版が完成したら、以下の拡張に挑戦してみてください:

  1. 編集機能: 既存の連絡先の電話番号やメールを更新する
  2. ソート機能: 名前順、追加日順で並び替え
  3. エクスポート: vCard形式(.vcf)での出力
  4. バックアップ: 削除前に確認を求め、バックアップファイルを作る
  5. 統計表示: 登録件数、メールアドレス登録率などを表示

これらはすべて、この講座で学んだ知識の範囲で実装可能です。

講座全体の振り返り

テーマ 核心概念
1 Pythonとは プログラミングの本質、Python の設計思想
2 環境構築 Python + VS Code のセットアップ
3 変数とデータ型 int, float, str, list の操作
4 条件分岐 if/elif/else、比較・論理演算子
5 繰り返し for, while, range, リスト内包表記
6 関数 def, return, スコープ, DRY原則
7 辞書とセット dict, set, キーバリュー, 集合演算
8 ファイル操作 open, csv, pathlib
9 エラーハンドリング try/except, EAFP, デバッグ技法
10 総合演習 CRUD アプリの設計と実装

次のステップ — この先の学習ロードマップ

Python入門を修了した後の学習パスは、興味の方向によって分岐します:

データ分析・AI方面: pandas → matplotlib → scikit-learn → TensorFlow/PyTorch Web開発方面: Flask → Django → データベース(SQLite/PostgreSQL)→ デプロイ 業務自動化方面: openpyxl(Excel操作)→ requests(Web API)→ selenium(ブラウザ自動化)

どの方向に進むにしても、この講座で学んだ「変数・制御構文・関数・データ構造・ファイル操作・エラー処理」は共通の土台です。この土台があれば、公式ドキュメントや他の入門書を読む力が身についているはずです。

推薦書籍: - 『退屈なことはPythonにやらせよう 第2版』Al Sweigart(オライリー・ジャパン)— 業務自動化の定番 - 『Pythonクラッシュコース 第3版』Eric Matthes(オライリー・ジャパン)— 次のレベルへ - 『Effective Python 第2版』Brett Slatkin(オライリー・ジャパン)— 中級者の必読書

プログラミングは「知っている」と「使える」の間に大きな溝があります。その溝を埋めるのは、自分で手を動かしてコードを書くことだけです。この講座がその第一歩になっていれば幸いです。