【Python内包表記を徹底解説】初心者でもスッキリ理解!書き方と実用例まとめ

python

「pythonのコードでよく見る [x for x in ...] って何?」
「for文をもっと短く書けるって聞いたけど…」
「内包表記って難しそう」

そんな疑問を解決するために、今回はpythonの内包表記について、初心者の方でも理解できるように詳しく説明していきます。

スポンサーリンク

内包表記とは?従来の書き方と比較してみよう

従来のfor文での書き方

まず、普通のfor文でリストを作る方法を見てみましょう。

# 1から5までの数字を2乗したリストを作る
squares = []
for x in range(1, 6):
    squares.append(x ** 2)
print(squares)  # [1, 4, 9, 16, 25]

内包表記での書き方

同じことを内包表記で書くと:

# 内包表記なら1行で完了!
squares = [x ** 2 for x in range(1, 6)]
print(squares)  # [1, 4, 9, 16, 25]

とてもシンプルになりました!

内包表記のメリット

内包表記の利点:
・コードが短くなる
・読みやすい(慣れれば)
・実行速度が速い
・Pythonらしい書き方
・一行で複雑な処理も可能

リスト内包表記の基本

基本的な構文

[式 for 変数 in イテラブル]
  • :各要素に対して実行する処理
  • 変数:イテラブルから取り出した各要素
  • イテラブル:リスト、range、文字列など

様々な例で理解を深めよう

# 例1:数値を10倍する
numbers = [1, 2, 3, 4, 5]
multiplied = [x * 10 for x in numbers]
print(multiplied)  # [10, 20, 30, 40, 50]

# 例2:文字列を大文字に変換
words = ["hello", "world", "python"]
upper_words = [word.upper() for word in words]
print(upper_words)  # ['HELLO', 'WORLD', 'PYTHON']

# 例3:文字列の長さを取得
lengths = [len(word) for word in words]
print(lengths)  # [5, 5, 6]

# 例4:rangeを使った数列生成
even_numbers = [x * 2 for x in range(5)]
print(even_numbers)  # [0, 2, 4, 6, 8]

より複雑な処理

# 文字列の処理
names = ["田中太郎", "佐藤花子", "山田次郎"]
formatted_names = [f"Mr./Ms. {name}" for name in names]
print(formatted_names)
# ['Mr./Ms. 田中太郎', 'Mr./Ms. 佐藤花子', 'Mr./Ms. 山田次郎']

# 数学的な処理
import math
angles = [0, 30, 45, 60, 90]
radians = [math.radians(angle) for angle in angles]
print(radians)
# [0.0, 0.5235987755982988, 0.7853981633974483, 1.0471975511965976, 1.5707963267948966]

# メソッドチェーン
texts = ["  Hello  ", "  World  ", "  Python  "]
cleaned = [text.strip().lower() for text in texts]
print(cleaned)  # ['hello', 'world', 'python']

条件付き内包表記

if文で要素をフィルタリング

特定の条件を満たす要素だけを抽出できます。

# 基本構文
[式 for 変数 in イテラブル if 条件]

実用例

# 偶数だけを抽出
numbers = range(10)
even_numbers = [x for x in numbers if x % 2 == 0]
print(even_numbers)  # [0, 2, 4, 6, 8]

# 奇数だけを抽出
odd_numbers = [x for x in numbers if x % 2 == 1]
print(odd_numbers)  # [1, 3, 5, 7, 9]

# 文字列の長さでフィルタリング
words = ["cat", "elephant", "dog", "hippopotamus", "rat"]
long_words = [word for word in words if len(word) > 3]
print(long_words)  # ['elephant', 'hippopotamus']

# 正の数だけを抽出
numbers = [-3, -1, 0, 2, 5, -2, 8]
positive_numbers = [x for x in numbers if x > 0]
print(positive_numbers)  # [2, 5, 8]

条件分岐(三項演算子)を使った変換

# 基本構文
[式1 if 条件 else 式2 for 変数 in イテラブル]

実用例

# 偶数は"偶数"、奇数は"奇数"のラベルを付ける
numbers = range(6)
labels = ["偶数" if x % 2 == 0 else "奇数" for x in numbers]
print(labels)  # ['偶数', '奇数', '偶数', '奇数', '偶数', '奇数']

# 正負の判定
numbers = [-2, -1, 0, 1, 2]
signs = ["負" if x < 0 else "零" if x == 0 else "正" for x in numbers]
print(signs)  # ['負', '負', '零', '正', '正']

# 成績判定
scores = [85, 92, 78, 65, 96]
grades = ["合格" if score >= 80 else "不合格" for score in scores]
print(grades)  # ['合格', '合格', '不合格', '不合格', '合格']

# 価格の割引適用
prices = [1000, 1500, 800, 2000]
discounted_prices = [price * 0.8 if price > 1000 else price for price in prices]
print(discounted_prices)  # [1000, 1200.0, 800, 1600.0]

三項演算子や条件分岐などをすると、ちょっと複雑になるので使用する場合は注意。

複数の条件を組み合わせ

# AND条件
numbers = range(20)
result = [x for x in numbers if x % 2 == 0 and x > 10]
print(result)  # [12, 14, 16, 18]

# OR条件
result = [x for x in numbers if x < 3 or x > 17]
print(result)  # [0, 1, 2, 18, 19]

# 複雑な条件
words = ["apple", "banana", "grape", "orange", "kiwi"]
result = [word.upper() for word in words if len(word) > 4 and "a" in word]
print(result)  # ['APPLE', 'BANANA', 'GRAPE', 'ORANGE']

辞書内包表記

基本的な辞書内包表記

# 基本構文
{キー: 値 for 変数 in イテラブル}

実用例

# 数字とその2乗の辞書
squares_dict = {x: x ** 2 for x in range(1, 6)}
print(squares_dict)  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 単語とその長さの辞書
words = ["apple", "banana", "cherry"]
word_lengths = {word: len(word) for word in words}
print(word_lengths)  # {'apple': 5, 'banana': 6, 'cherry': 6}

# 学生の成績辞書
students = ["太郎", "花子", "次郎"]
scores = [85, 92, 78]
grade_dict = {student: score for student, score in zip(students, scores)}
print(grade_dict)  # {'太郎': 85, '花子': 92, '次郎': 78}

条件付き辞書内包表記

# 合格者のみの辞書
students_scores = {"太郎": 85, "花子": 92, "次郎": 65, "美香": 78}
passed_students = {name: score for name, score in students_scores.items() if score >= 80}
print(passed_students)  # {'太郎': 85, '花子': 92}

# 値の変換を含む辞書
temperatures_c = {"東京": 25, "大阪": 28, "札幌": 20}
temperatures_f = {city: (temp * 9/5) + 32 for city, temp in temperatures_c.items()}
print(temperatures_f)  # {'東京': 77.0, '大阪': 82.4, '札幌': 68.0}

既存辞書の変換

# キーと値を入れ替え
original = {"a": 1, "b": 2, "c": 3}
swapped = {value: key for key, value in original.items()}
print(swapped)  # {1: 'a', 2: 'b', 3: 'c'}

# 辞書の値を変換
prices = {"apple": 100, "banana": 80, "orange": 120}
# 税込価格(10%)に変換
tax_included = {item: int(price * 1.1) for item, price in prices.items()}
print(tax_included)  # {'apple': 110, 'banana': 88, 'orange': 132}

集合内包表記

基本的な集合内包表記

# 基本構文
{式 for 変数 in イテラブル}

実用例

# 重複を除去した平方数
numbers = [1, 2, 2, 3, 3, 4, 5]
unique_squares = {x ** 2 for x in numbers}
print(unique_squares)  # {1, 4, 9, 16, 25}

# 文字列の長さ(重複なし)
words = ["apple", "banana", "grape", "kiwi", "mango"]
unique_lengths = {len(word) for word in words}
print(unique_lengths)  # {4, 5, 6}

# 文字列に含まれる文字の種類
text = "hello world"
unique_chars = {char for char in text if char != " "}
print(unique_chars)  # {'e', 'h', 'l', 'o', 'r', 'w', 'd'}

ネストした内包表記

2次元リストの処理

# 2次元リストの平坦化
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# 条件付きの平坦化
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
even_numbers = [num for row in matrix for num in row if num % 2 == 0]
print(even_numbers)  # [2, 4, 6, 8]

# 2次元リストの作成
multiplication_table = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print(multiplication_table)  # [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

座標の生成

# 座標ペアの生成
coordinates = [(x, y) for x in range(3) for y in range(3)]
print(coordinates)
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

# 条件付き座標生成
coordinates = [(x, y) for x in range(5) for y in range(5) if x + y <= 3]
print(coordinates)
# [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (3, 0)]

実践的な活用例

データ処理での活用

# CSVデータの処理(想定)
data = [
    ["太郎", "25", "男性"],
    ["花子", "30", "女性"],
    ["次郎", "35", "男性"]
]

# 辞書のリストに変換
headers = ["名前", "年齢", "性別"]
people = [{headers[i]: row[i] for i in range(len(headers))} for row in data]
print(people)
# [{'名前': '太郎', '年齢': '25', '性別': '男性'}, ...]

# 特定条件でフィルタリング
adults = [person for person in people if int(person["年齢"]) >= 30]
print(adults)

ファイル処理での活用

# ファイルの行処理(例)
# lines = ["  line 1  ", "", "  line 2  ", "  line 3  "]

# 空白行を除去し、前後の空白を削除
# cleaned_lines = [line.strip() for line in lines if line.strip()]
# print(cleaned_lines)  # ['line 1', 'line 2', 'line 3']

# 特定の拡張子のファイルを抽出
filenames = ["doc.txt", "image.jpg", "data.csv", "script.py", "readme.md"]
python_files = [f for f in filenames if f.endswith(".py")]
print(python_files)  # ['script.py']

text_files = [f for f in filenames if f.endswith((".txt", ".md"))]
print(text_files)  # ['doc.txt', 'readme.md']

数学的処理での活用

# 素数の判定と抽出
def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

primes = [n for n in range(2, 30) if is_prime(n)]
print(primes)  # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

# フィボナッチ数列の生成(一定範囲内)
def fibonacci_up_to(limit):
    fib = [0, 1]
    while fib[-1] + fib[-2] <= limit:
        fib.append(fib[-1] + fib[-2])
    return fib

fib_numbers = fibonacci_up_to(100)
even_fibs = [n for n in fib_numbers if n % 2 == 0]
print(even_fibs)  # [0, 2, 8, 34]

内包表記使用時の注意点

読みやすさとのバランス

# 複雑すぎて読みにくい
complex_result = [
    x * y for x in range(10) 
    for y in range(10) 
    if x % 2 == 0 and y % 3 == 0 and x * y > 10
]

# 読みやすく分割
def is_valid_pair(x, y):
    return x % 2 == 0 and y % 3 == 0 and x * y > 10

readable_result = [
    x * y for x in range(10) for y in range(10) 
    if is_valid_pair(x, y)
]

# または通常のfor文を使用
readable_result2 = []
for x in range(10):
    for y in range(10):
        if is_valid_pair(x, y):
            readable_result2.append(x * y)

パフォーマンスの考慮

# 無駄な処理を含む
expensive_list = [expensive_function(x) for x in range(1000)]

# 条件で事前にフィルタリング
def expensive_function(x):
    # 重い処理のシミュレーション
    return x ** 3

efficient_list = [
    expensive_function(x) for x in range(1000) 
    if x % 10 == 0  # 必要な要素のみ処理
]

副作用のある処理は避ける

# 副作用のある処理(推奨されない)
count = 0
def increment_and_return(x):
    global count
    count += 1
    return x * 2

# このような使い方は避ける
# result = [increment_and_return(x) for x in range(10)]

# 純粋な関数を使用
def pure_function(x):
    return x * 2

result = [pure_function(x) for x in range(10)]

よくある疑問

Q
内包表記と通常のfor文、どちらが速い?
A

一般的に内包表記の方が高速です。ただし、複雑な処理では可読性を優先してfor文を使うことも重要です。

Q
何重までのネストが適切?
A

2重まで(for x in ... for y in ...)が読みやすさの限界です。3重以上は通常のfor文を使いましょう。

Q
内包表記でエラーハンドリングはできる?
A

直接はできません。エラーが発生する可能性がある場合は、事前に条件でフィルタリングするか、通常のfor文を使用してください。

# エラーが発生する可能性がある例
numbers = [1, 2, 0, 4, 5]

# ゼロ除算エラーが発生
# result = [10 / x for x in numbers]

# 事前にフィルタリング
result = [10 / x for x in numbers if x != 0]
print(result)  # [10.0, 5.0, 2.5, 2.0]
Q
内包表記でbreakやcontinueは使える?
A

使えません。このような制御が必要な場合は通常のfor文を使用してください。

まとめ

pythonの内包表記は、コードを簡潔で読みやすくする強力な機能です。

今回学んだポイント

  • 基本構文[式 for 変数 in イテラブル]
  • 条件付きifでフィルタリング、三項演算子で変換
  • 応用:辞書内包表記、集合内包表記、ネスト処理
  • 実践活用:データ処理、ファイル操作、数学的計算
  • 注意点:可読性とパフォーマンスのバランス

コメント

タイトルとURLをコピーしました