Pythonのリスト内包表記とは?基本から実務での活用まで完全解説
こんにちは、とまだです。
Pythonでリストを扱っていて、こんなコードを見たことはありませんか?
squares = [x**2 for x in range(10)]
「なんだこの書き方は...」と思いましたよね。
私も最初は戸惑いました。
でも実は、これがPythonの「リスト内包表記」という強力な機能なんです。
今回は、リスト内包表記の基本から実務での活用まで、初心者の方でも理解できるように解説していきます。
リスト内包表記とは?基本的な仕組みを理解する
リスト内包表記は、既存のリストから新しいリストを作るための簡潔な記法です。
従来のfor文を使った方法と比較してみます。
従来の書き方
# 0から9までの数値を2乗したリストを作る
squares = []
for x in range(10):
squares.append(x**2)
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4行のコードが必要でした。
リスト内包表記での書き方
# 同じ処理を1行で実現
squares = [x**2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
たった1行で同じ結果が得られます。
コードの行数が減るだけでなく、「リストを作っている」という意図が明確になります。
基本構文:3つの要素を押さえる
リスト内包表記の基本構文はシンプルです。
[式 for 変数 in イテラブル]
構成要素は以下の3つです。
- 式:各要素に適用する処理
- 変数:イテラブルから取り出した要素を格納
- イテラブル:リスト、range、文字列など繰り返し可能なオブジェクト
具体例で理解を深める
# 文字列のリストを大文字に変換
names = ["alice", "bob", "charlie"]
upper_names = [name.upper() for name in names]
print(upper_names) # ['ALICE', 'BOB', 'CHARLIE']
# 数値リストから偶数だけを2倍にする
numbers = [1, 2, 3, 4, 5, 6]
doubled_evens = [n * 2 for n in numbers if n % 2 == 0]
print(doubled_evens) # [4, 8, 12]
条件付きリスト内包表記:フィルタリング機能
if文を追加することで、条件に合う要素だけを抽出できます。
[式 for 変数 in イテラブル if 条件]
実践的な使用例
# APIレスポンスから有効なデータだけを抽出
api_responses = [
{"id": 1, "status": "active", "name": "User1"},
{"id": 2, "status": "inactive", "name": "User2"},
{"id": 3, "status": "active", "name": "User3"},
]
active_users = [user["name"] for user in api_responses if user["status"] == "active"]
print(active_users) # ['User1', 'User3']
複雑な条件:if-else を使う場合
条件によって異なる処理を行いたい場合は、構文が少し変わります。
[条件成立時の式 if 条件 else 条件不成立時の式 for 変数 in イテラブル]
# 数値の正負でラベルを付ける
numbers = [-2, -1, 0, 1, 2]
labels = ["negative" if n < 0 else "positive" if n > 0 else "zero" for n in numbers]
print(labels) # ['negative', 'negative', 'zero', 'positive', 'positive']
実務でよく使う5つのパターン
1. データ型の変換
# 文字列の数値リストを整数に変換
str_prices = ["100", "200", "300"]
int_prices = [int(price) for price in str_prices]
print(int_prices) # [100, 200, 300]
2. 辞書からの値抽出
# 商品情報から価格だけを抽出
products = [
{"name": "商品A", "price": 1000},
{"name": "商品B", "price": 2000},
{"name": "商品C", "price": 1500}
]
prices = [product["price"] for product in products]
print(prices) # [1000, 2000, 1500]
3. 文字列処理
# CSVデータのクレンジング
csv_data = [" apple ", "banana\n", "\torange\t"]
cleaned = [item.strip() for item in csv_data]
print(cleaned) # ['apple', 'banana', 'orange']
4. ファイルパスの処理
import os
# 特定の拡張子のファイルだけを抽出
files = ["document.txt", "image.jpg", "script.py", "data.csv", "readme.txt"]
txt_files = [f for f in files if f.endswith('.txt')]
print(txt_files) # ['document.txt', 'readme.txt']
5. 数値計算の一括処理
# 税込み価格の計算
prices = [1000, 2000, 3000]
tax_rate = 1.1
prices_with_tax = [int(price * tax_rate) for price in prices]
print(prices_with_tax) # [1100, 2200, 3300]
ネストしたリスト内包表記
二次元リストの処理も可能ですが、可読性に注意が必要です。
基本的なネスト
# 2次元リストを1次元に平坦化
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]
読みやすさを重視した書き方
複雑なネストは避け、必要に応じて通常のfor文を使います。
# 可読性を重視した例
result = []
for row in matrix:
for num in row:
if num % 2 == 0: # 偶数のみ
result.append(num * 2)
パフォーマンスと最適化
リスト内包表記 vs for文
一般的に、リスト内包表記の方が若干高速です。
import timeit
# for文での実装
def using_for_loop():
result = []
for i in range(1000):
result.append(i**2)
return result
# リスト内包表記での実装
def using_comprehension():
return [i**2 for i in range(1000)]
# 実行時間の比較
for_time = timeit.timeit(using_for_loop, number=10000)
comp_time = timeit.timeit(using_comprehension, number=10000)
print(f"for文: {for_time:.4f}秒")
print(f"内包表記: {comp_time:.4f}秒")
# 結果例:for文: 0.8234秒、内包表記: 0.6782秒
メモリ効率を考慮する場合
大量のデータを扱う場合は、ジェネレータ式を検討します。
# リスト内包表記(全データをメモリに展開)
squares_list = [x**2 for x in range(1000000)]
# ジェネレータ式(必要な時に値を生成)
squares_gen = (x**2 for x in range(1000000))
# メモリ使用量が大きく異なる
import sys
print(f"リスト: {sys.getsizeof(squares_list)} bytes")
print(f"ジェネレータ: {sys.getsizeof(squares_gen)} bytes")
使用時の注意点とベストプラクティス
1. 可読性を最優先に
# 悪い例:複雑すぎる
result = [[y for y in range(x) if y % 2 == 0] for x in range(10) if x > 5]
# 良い例:意図が明確
def get_even_numbers(limit):
return [y for y in range(limit) if y % 2 == 0]
result = [get_even_numbers(x) for x in range(10) if x > 5]
2. 副作用のある処理は避ける
# 悪い例:副作用がある
items = []
[items.append(x) for x in range(10)] # リスト内包表記の誤用
# 良い例:純粋な変換処理
items = [x for x in range(10)]
3. 適切なエラーハンドリング
# データに欠損がある場合の対処
data = ["1", "2", "invalid", "4"]
# エラーが発生する可能性がある処理
def safe_int_convert(value):
try:
return int(value)
except ValueError:
return None
# Noneを除外して変換
valid_numbers = [safe_int_convert(x) for x in data if safe_int_convert(x) is not None]
print(valid_numbers) # [1, 2, 4]
他の内包表記との組み合わせ
辞書内包表記
# リストから辞書を作成
names = ["alice", "bob", "charlie"]
name_lengths = {name: len(name) for name in names}
print(name_lengths) # {'alice': 5, 'bob': 3, 'charlie': 7}
集合内包表記
# 重複を自動的に除去
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique_squares = {n**2 for n in numbers}
print(unique_squares) # {1, 4, 9, 16}
まとめ
リスト内包表記は、Pythonらしい簡潔なコードを書くための重要な機能です。
基本の形 [式 for 変数 in イテラブル] から始めて、徐々に条件付きやネストした形に慣れていきましょう。
ただし、可読性を犠牲にしてまで使う必要はありません。
チームメンバーが理解しやすいコードを書くことが最も重要です。
実務では、データの変換やフィルタリングで頻繁に使うことになるので、ぜひマスターしてください。
著者について

とまだ
フルスタックエンジニア
Learning Next の創設者。Ruby on Rails と React を中心に、プログラミング教育に情熱を注いでいます。初心者が楽しく学べる環境作りを目指しています。
著者の詳細を見る →