Python 内包表記の基礎|リストを簡潔に作る方法

Python 内包表記の基本的な使い方と実用的な活用法を初心者向けに解説。リストを効率的に作成する方法を学びましょう。

Learning Next 運営
20 分で読めます

Python 内包表記の基礎|リストを簡潔に作る方法

みなさん、Pythonでリストを作るとき、for文で何行も書いていませんか?

「もっと簡潔に書けたらいいのに」と思ったことはありませんか?

実は、Pythonには**内包表記(リスト内包表記)**という素晴らしい機能があります。 これを使えば、複雑なリストを1行で作成できるんです。

この記事では、内包表記の基本から実用的な使い方まで、分かりやすく解説します。 あなたもPythonらしい美しいコードを書けるようになりますよ!

内包表記って何?

内包表記は、既存のリストから新しいリストを効率的に作成するPythonの機能です。

簡単に言うと、リストを作る便利な書き方なんです。

基本的な書き方

内包表記の基本的な構文を見てみましょう。

# 基本的な構文
[for 変数 in イテラブル]
# 例
numbers = [1, 2, 3, 4, 5]
squared = [x * x for x in numbers]
print(squared) # [1, 4, 9, 16, 25]

この例では、numbersリストの各要素を2乗して新しいリストsquaredを作っています。 x * xが式、xが変数、numbersがイテラブルです。

とてもシンプルで分かりやすいですね。

従来の方法との比較

for文を使った従来の方法と比較してみましょう。

# 従来の方法(for文)
numbers = [1, 2, 3, 4, 5]
squared = []
for x in numbers:
squared.append(x * x)
print(squared) # [1, 4, 9, 16, 25]
# 内包表記
squared = [x * x for x in numbers]
print(squared) # [1, 4, 9, 16, 25]

従来の方法では4行必要でしたが、内包表記なら1行で済みます。

しかも、処理の内容がとても分かりやすいです。

内包表記のメリット

内包表記には、以下のようなメリットがあります。

  • 簡潔性: 1行で複雑なリストを作成できる
  • 読みやすさ: 何をしているかが一目で分かる
  • 高速処理: 従来のfor文よりも高速
  • Pythonらしさ: Pythonらしい美しいコードが書ける

Pythonプログラマーなら、ぜひ覚えておきたい機能です。

基本的な使い方

様々な基本的な使い方を見てみましょう。

数値の変換

数値を変換するシンプルな例から始めましょう。

# 数値を2倍する
numbers = [1, 2, 3, 4, 5]
doubled = [x * 2 for x in numbers]
print(doubled) # [2, 4, 6, 8, 10]
# 数値を文字列に変換
numbers = [1, 2, 3, 4, 5]
strings = [str(x) for x in numbers]
print(strings) # ['1', '2', '3', '4', '5']

最初の例では、各数値を2倍しています。 2番目の例では、数値を文字列に変換しています。

どちらも、1行で処理が完了しています。

range()との組み合わせ

range()関数と組み合わせると、さらに便利です。

# range()と組み合わせる
squares = [x * x for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
# 偶数のみ生成
evens = [x for x in range(2, 11, 2)]
print(evens) # [2, 4, 6, 8, 10]

range(1, 6)は1から5までの数値を生成します。 range(2, 11, 2)は2から10まで、2つずつ増加させながら数値を生成します。

効率的に数値リストを作成できますね。

文字列の処理

文字列の処理も簡単にできます。

# 文字列を大文字に変換
words = ["hello", "world", "python"]
upper_words = [word.upper() for word in words]
print(upper_words) # ['HELLO', 'WORLD', 'PYTHON']
# 文字列の長さを取得
lengths = [len(word) for word in words]
print(lengths) # [5, 5, 6]

最初の例では、各単語を大文字に変換しています。 2番目の例では、各単語の文字数を取得しています。

文字列の処理も、とても簡潔に記述できます。

条件付き内包表記

条件を組み合わせると、さらに柔軟なリスト作成ができます。

条件でフィルタリング

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

# 偶数のみを抽出
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = [x for x in numbers if x % 2 == 0]
print(evens) # [2, 4, 6, 8, 10]
# 正数のみを抽出
numbers = [-2, -1, 0, 1, 2, 3]
positives = [x for x in numbers if x > 0]
print(positives) # [1, 2, 3]

最初の例では、x % 2 == 0で偶数かどうかを判定しています。 2番目の例では、x > 0で正数かどうかを判定しています。

if文を使って、必要な要素だけを抽出できます。

条件付きの変換

条件に応じて、異なる処理を適用することもできます。

# 偶数は2倍、奇数はそのまま
numbers = [1, 2, 3, 4, 5]
modified = [x * 2 if x % 2 == 0 else x for x in numbers]
print(modified) # [1, 4, 3, 8, 5]
# 正数は平方根、負数は絶対値
import math
numbers = [-4, -1, 0, 1, 4, 9]
processed = [math.sqrt(x) if x >= 0 else abs(x) for x in numbers]
print(processed) # [4, 1, 0.0, 1.0, 2.0, 3.0]

最初の例では、偶数は2倍、奇数はそのままにしています。 2番目の例では、正数は平方根、負数は絶対値を取っています。

条件によって異なる処理を適用できるので、とても柔軟です。

複数の条件

複数の条件を組み合わせることもできます。

# 複数条件でフィルタリング
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
filtered = [x for x in numbers if x % 2 == 0 and x > 5]
print(filtered) # [6, 8, 10]
# 文字列の複数条件
words = ["apple", "banana", "cherry", "date", "elderberry"]
filtered_words = [word for word in words if len(word) > 5 and 'a' in word]
print(filtered_words) # ['banana', 'elderberry']

最初の例では、偶数かつ5より大きい数を抽出しています。 2番目の例では、5文字より長くて'a'を含む単語を抽出しています。

andorを使って、複雑な条件も設定できます。

ネストした内包表記

内包表記は、ネストすることも可能です。

2次元リストの作成

2次元のデータ構造を作成してみましょう。

# 九九表を作成
multiplication_table = [[i * j for j in range(1, 10)] for i in range(1, 10)]
for row in multiplication_table:
print(row)
# 座標のリストを作成
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)]

最初の例では、九九表を2次元リストで作成しています。 外側の内包表記で行を、内側の内包表記で列を作成しています。

2番目の例では、座標のペアを作成しています。

2次元リストの平坦化

2次元リストを1次元に変換することもできます。

# 2次元リストを1次元にする
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [item for row in matrix for item in row]
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 条件付きの平坦化
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
filtered_flat = [item for row in matrix for item in row if item % 2 == 0]
print(filtered_flat) # [2, 4, 6, 8]

最初の例では、2次元リストを1次元リストに変換しています。 2番目の例では、偶数だけを抽出しながら平坦化しています。

複雑な構造の変換も、内包表記で簡潔に書けます。

辞書・集合の内包表記

リスト以外にも、辞書や集合の内包表記があります。

辞書内包表記

辞書も内包表記で効率的に作成できます。

# 辞書内包表記の基本
numbers = [1, 2, 3, 4, 5]
squared_dict = {x: x * x for x in numbers}
print(squared_dict) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# 文字列の長さを辞書にする
words = ["apple", "banana", "cherry"]
length_dict = {word: len(word) for word in words}
print(length_dict) # {'apple': 5, 'banana': 6, 'cherry': 6}

最初の例では、数値をキー、その2乗を値とする辞書を作成しています。 2番目の例では、単語をキー、その文字数を値とする辞書を作成しています。

{key: value for item in iterable}の形式で書きます。

集合内包表記

集合の内包表記では、重複を除いた要素を作成できます。

# 集合内包表記の基本
numbers = [1, 2, 2, 3, 3, 4, 5]
unique_squares = {x * x for x in numbers}
print(unique_squares) # {1, 4, 9, 16, 25}
# 条件付きの集合作成
text = "Hello World"
vowels = {char.lower() for char in text if char.lower() in 'aeiou'}
print(vowels) # {'e', 'o'}

最初の例では、重複する数値があっても、結果の集合には重複がありません。 2番目の例では、文字列から母音だけを抽出して集合を作成しています。

{expression for item in iterable}の形式で書きます。

実践的な活用例

実際のプログラミングでよく使われる例を見てみましょう。

データ処理

CSVデータのような構造化データの処理例です。

# CSVデータの処理(仮想的な例)
csv_data = [
["Alice", "25", "Engineer"],
["Bob", "30", "Designer"],
["Charlie", "35", "Manager"]
]
# 名前のリストを作成
names = [row[0] for row in csv_data]
print(names) # ['Alice', 'Bob', 'Charlie']
# 年齢を整数に変換
ages = [int(row[1]) for row in csv_data]
print(ages) # [25, 30, 35]
# 30歳以上の人を抽出
adults = [row[0] for row in csv_data if int(row[1]) >= 30]
print(adults) # ['Bob', 'Charlie']

最初の例では、各行の最初の要素(名前)を抽出しています。 2番目の例では、文字列の年齢を整数に変換しています。 3番目の例では、30歳以上の人の名前だけを抽出しています。

データ処理でとても便利に使えます。

ファイル処理

ファイル名の処理例も見てみましょう。

# ファイル名の処理
import os
# 特定の拡張子のファイルを抽出
files = ["document.txt", "image.jpg", "script.py", "data.csv", "photo.png"]
text_files = [file for file in files if file.endswith('.txt')]
print(text_files) # ['document.txt']
# ファイル名から拡張子を除去
base_names = [os.path.splitext(file)[0] for file in files]
print(base_names) # ['document', 'image', 'script', 'data', 'photo']

最初の例では、.txtで終わるファイルだけを抽出しています。 2番目の例では、拡張子を除いたファイル名を取得しています。

ファイル処理でも内包表記が活躍します。

数値計算

統計的な計算でも内包表記が使えます。

# 統計的な計算
scores = [85, 90, 78, 92, 88, 76, 95, 82]
# 平均点以上の点数を抽出
average = sum(scores) / len(scores)
above_average = [score for score in scores if score >= average]
print(f"平均点: {average}")
print(f"平均点以上: {above_average}")
# 偏差を計算
deviations = [score - average for score in scores]
print(f"偏差: {deviations}")

最初の例では、平均点を計算して、平均点以上の点数を抽出しています。 2番目の例では、各点数の偏差を計算しています。

数値計算でも、内包表記で効率的に処理できます。

性能とメモリ効率

内包表記の性能面でのメリットを確認しましょう。

速度の比較

従来のfor文と内包表記の速度を比較してみます。

import time
# 大きなリストでの比較
n = 100000
# 従来の方法
start = time.time()
result1 = []
for i in range(n):
result1.append(i * i)
time1 = time.time() - start
# 内包表記
start = time.time()
result2 = [i * i for i in range(n)]
time2 = time.time() - start
print(f"従来の方法: {time1:.4f}秒")
print(f"内包表記: {time2:.4f}秒")
# 内包表記の方が一般的に高速

このコードでは、10万個の要素を持つリストを作成して処理時間を比較しています。

一般的に、内包表記の方が従来のfor文よりも高速です。

メモリ効率

ジェネレータ式を使うと、メモリ効率も向上します。

# ジェネレータ式でメモリ効率を向上
large_numbers = (i * i for i in range(1000000)) # ジェネレータ式
print(type(large_numbers)) # <class 'generator'>
# 必要な時だけ値を生成
for i, value in enumerate(large_numbers):
if i >= 10: # 最初の10個だけ処理
break
print(value)

[]の代わりに()を使うと、ジェネレータ式になります。 ジェネレータ式は、必要な時だけ値を生成するので、メモリ効率が良いです。

大きなデータを扱う時に便利です。

注意点とベストプラクティス

内包表記を使用する際の注意点を確認しましょう。

可読性を保つ

内包表記は便利ですが、複雑すぎると読みにくくなります。

# 推奨: 読みやすい内包表記
numbers = [1, 2, 3, 4, 5]
squares = [x * x for x in numbers]
# 非推奨: 複雑すぎる内包表記
# result = [x * y for x in range(10) for y in range(10) if x % 2 == 0 and y % 3 == 0 and x + y > 5]

複雑すぎる内包表記は、可読性を損なうため避けましょう。

シンプルで分かりやすい内包表記を心がけることが大切です。

適切な使い分け

処理が複雑な場合は、従来のfor文を使う方が良い場合もあります。

# 内包表記が適している場合
simple_transform = [x * 2 for x in numbers]
# 従来のfor文が適している場合(複雑な処理)
results = []
for item in complex_data:
# 複雑な処理が必要な場合
processed = complex_function(item)
if complex_condition(processed):
results.append(processed)

処理が単純な場合は内包表記を使い、複雑な場合は従来のfor文を使いましょう。

適切な使い分けが重要です。

デバッグの考慮

デバッグが必要な場合は、従来のfor文の方が適している場合があります。

# デバッグしやすい書き方
numbers = [1, 2, 3, 4, 5]
results = []
for x in numbers:
result = x * x # ここでブレークポイントを設定可能
results.append(result)
# 内包表記(デバッグが困難)
results = [x * x for x in numbers]

従来のfor文なら、途中でブレークポイントを設定してデバッグできます。

デバッグが必要な場合は、従来のfor文を使うことも検討しましょう。

まとめ

内包表記は、Pythonでリストを効率的に作成するための強力な機能です。

今回学んだポイント

  • 内包表記で従来のfor文よりも簡潔にリストを作成できる
  • 条件付き内包表記で柔軟なフィルタリングが可能
  • 辞書や集合の内包表記も活用できる
  • 性能面でのメリットがある
  • 可読性を保つことが重要

内包表記は、Pythonらしい簡潔で読みやすいコードを書くために欠かせない機能です。

まずは基本的な使い方から始めて、徐々に複雑な処理にも応用してみましょう。

シンプルなリスト変換から始めて、内包表記の便利さを体感してください!

関連記事