Pythonのイテラブルの理解と活用は、上級コーディングの基本。イテラブルは、繰り返し処理を行うことができるオブジェクトで、要素を順次走査することを可能にし、オブジェクトやデータ構造内の要素にアクセスしたり、操作したりするための重要なツールです。

今回は、Python組み込みの繰り返し可能なデータ型、リスト、タプル、辞書、文字列、集合に焦点を当て、イテラブルの適切な使用方法をご紹介。また、独自のイテレータを作成し、高度な操作を行う方法についても取り上げます。

イテラブルの繰り返し処理

Pythonでは、for文を使用してさまざまなイテラブルを繰り返し処理(ループ処理、反復処理とも)を行います。これにより、リスト、セット、辞書内の個々の項目に対して、シーケンスの操作、実行を行うことができます。

Pythonのfor文は、 Javaのような他のオブジェクト指向言語での有用性とは異なり、よりイテレータメソッドに近い動作になります。以下、さまざまなイテラブルの繰り返し処理をご紹介します。

1. リストの繰り返し処理

Pythonにおけるリストは、複数の要素を順にまとめたものです。for文を使って簡単に繰り返し処理を行うことができます。

fruits_list = ["りんご", "マンゴー", "もも", "オレンジ", "バナナ"]

for fruit in fruits_list:
    print(fruit)

上のコードでは、fruitがイテレータ(次の要素に順にアクセスする機能を提供するもの)となり、リストの各要素を走査、表示します。繰り返し処理は、リストの最後の要素を評価すると終了します。この結果は以下のようになります。

りんご
マンゴー
もも
オレンジ
バナナ

2. タプルの繰り返し処理

タプルはリストに似ていますが、リストが可変であるのに対して、タプルは不変(変更不可)です。リストと同じように繰り返し処理を行うことができます。

fruits_tuple = ("りんご", "マンゴー", "もも", "オレンジ", "バナナ")

for fruit in fruits_tuple:
	print(fruit)

この例では、forfruit変数がタプルの現在の要素の値を繰り返し取得します。出力は以下のようになります。

りんご
マンゴー
もも
オレンジ
バナナ

3. 集合の繰り返し処理

集合は、順位付けなしで一意の要素をまとめたものです。以下のように、forで繰り返し処理を行うことができます。

fruits_set = {"りんご", "マンゴー", "もも", "オレンジ", "バナナ"}

for fruit in fruits_set:
	print(fruit)

集合には順序がないため、出力が定義した順序と同じになるとは限りません。fruit変数が現在の集合の要素を繰り返し取得し、以下のような出力(順序は異なる可能性あり)を返します。

マンゴー
バナナ
もも
りんご
オレンジ

4. 文字列の繰り返し処理

文字列(その名の通り、文字の並び)は、一文字ずつ繰り返し処理を行うことができます。

string = "Kinsta"

for char in string:
	print(char)

上のコードは文字列「Kinsta」をループし、各文字を改行します。char変数が文字列の現在の文字の値を繰り返し取得します。出力は以下のとおりです。

K
i
n
s
t
a

5. 辞書の繰り返し処理

リスト、タプル、集合、文字列と同じように、辞書にもforを使って繰り返し処理を行うことができますが、キーと値のペアを使って要素を格納する点が異なります。辞書の場合、繰り返し処理にはさまざまなアプローチがあるため、異色なデータ型と言えます。以下、いくつか例をご紹介します。

  • キーの繰り返し処理
    countries_capital = {
        "アメリカ合衆国": "ワシントンD.C.",
        "オーストラリア": "キャンベラ",
        "フランス": "パリ",
        "エジプト": "カイロ",
        "日本": "東京"
    }
    
    for country in countries_capital.keys():
        print(country)

    上のコードでは、辞書countries_capitalを定義し、国名をキー、それぞれの首都を値としています。for文がkeys関数を使用して、countries_capital辞書のキーをループし、関数が辞書のキーの一覧を表示するビューオブジェクトを返します。country変数が現在のキーの値を繰り返し取得し、以下のような出力になります。

    アメリカ合衆国
    オーストラリア
    フランス
    エジプト
    日本
  • 値の繰り返し処理
    countries_capital = {
        "アメリカ合衆国": "ワシントンD.C.",
        "オーストラリア": "キャンベラ",
        "フランス": "パリ",
        "エジプト": "カイロ",
        "日本": "東京"
    }
    
    for capital in countries_capital.values():
        print(capital)

    上のコードでは、for文がvalues関数を使用して、countries_capital辞書の値をループします。関数はディクショナリ内の値の一覧を表示するビューオブジェクトを返すため、すべての値を簡単に繰り返し処理することができます。capital変数がリスト内の現在の値を繰り返し取得し、出力は以下のようになります。

    ワシントンD.C.
    キャンベラ
    パリ
    カイロ
    東京
  • キーと値のペアの繰り返し処理
    countries_capital = {
         "アメリカ合衆国": "ワシントンD.C.",
        "オーストラリア": "キャンベラ",
        "フランス": "パリ",
        "エジプト": "カイロ",
        "日本": "東京"
    }
    
    for country, capital in countries_capital.items():
        print(country, ":", capital)

    上のコードは、items関数を使用して、countries_capital辞書のキーと値の両方をループ。items関数が辞書内のキーと値のタプルの一覧を表示するビューオブジェクトを返します。リスト内の現在の要素からキーと値のペアを繰り返し取得し、countryおよびcapital変数には、それぞれ対応するキーと値が代入されます。出力は以下のとおりです。

    アメリカ合衆国 : ワシントンD.C.
    オーストラリア : キャンベラ
    フランス : パリ
    エジプト : カイロ
    日本 : 東京

enumerate関数を使った高度な繰り返し処理

要素のインデックスと対応する値の両方を返しながら、イテラブルの繰り返し処理を行う別の方法として、enumerate関数も使用することができます。以下例を見てみます。

fruits_list = ["りんご", "マンゴー", "もも", "オレンジ", "バナナ"]

for index, fruit in enumerate(fruits_list):
    print(fruit, index)

出力は以下のようになります。

りんご 0
マンゴー 1
もも 2
オレンジ 3
バナナ 4

enumerate関数では、0以外にも繰り返し処理の開始インデックスを指定可能です。上の例を次のようにすることもできます。

fruits_list = ["りんご", "マンゴー", "もも", "オレンジ", "バナナ"]
for index, fruit in enumerate(fruits_list, start = 2):
    print(fruit, index)

この結果は、以下のようになります。

りんご 2
マンゴー 3
もも 4
オレンジ 5
バナナ 6

この例では、配列の開始インデックスを指定していますが、enumerate関数は、Pythonデフォルトのリストのように、イテラブル要素にゼロベースのインデックスを適用しません。リストの最初の要素から最後の要素まで、単に開始値が追加されます。

ジェネレーター式の実装方法

ジェネレーターは、Pythonの反復可能な式で、リストや集合、辞書のような組み込みの型を明示的に作成することなく、ジェネレーターオブジェクトを作成することができます。生成ロジックに基づいた値を生成可能です。

ジェネレーターは、yield文を使用して、生成された値を1つずつ返します。例を挙げてみます。

def even_generator(n):
    counter = 0
    while counter <= n:
        if counter % 2 == 0:
            yield counter
        counter += 1

for num in even_generator(20):
    print(num)

このコードでは、yield文を使用して、0から指定されたnまでの偶数列を生成するeven_generator関数を定義しています。ループを使用してこれらの値を生成し、numイテレータを使用して結果を繰り返し処理し、指定された範囲内のすべての値の評価を保証します。上のコードは、0から20までの偶数のリストを出力します。

0
2
4
6
8
10
12
14
16
18
20

ジェネレーター式を使用すると、より簡潔になり、たとえばループロジックも組み込んだジェネレーター関数を作ることができます。

cube = (num ** 3 for num in range(1, 6))
for c in cube:
    print(c)

この例では、1から6までの範囲の値の3乗を計算する関数の結果に、cube変数を代入します。その後、指定された範囲内の値をループし、計算結果を順に出力します。

1
8
27
64
125

独自のイテレータを作成する方法

Pythonでは、イテレータを使用することで、イテラブルの操作をさらにカスタマイズすることができます。イテレータオブジェクトは、イテレータプロトコルを実装し、__iter__()__next__()の2つの関数を持ちます。__iter__()は、イテレータオブジェクト、__next__()はイテラブルなコンテナの次の値を返します。例を見てみます。

even_list = [2, 4, 6, 8, 10]
my_iterator = iter(even_list)
print(next(my_iterator)) # Prints 2
print(next(my_iterator)) # Prints 4
print(next(my_iterator)) # Prints 6

上のコードは、iter()を使用して、リストからイテレータオブジェクト(my_iterator)を作成します。リストの各要素にアクセスするには、next()でイテレータオブジェクトをラップします。リストでは順序が決まっているため、要素は順番に返されます。

独自イテレータの作成は、同時にメモリに読み込めないような大きなデータセットを含む操作に理想的です。メモリは高価で、容量の制約を受けやすいため、これによってデータセット全体を読み込むことなく、データ要素を個別に処理することができます。

繰り返し可能な関数

Pythonでは、リスト要素を移動、操作、検証するために以下のような関数を使用します。

  • sum—コレクションが数値型(整数、浮動小数点数、複素数)である場合に、与えられたイテラブルの合計を返す
  • any—イテラブルのいずれかが真の場合はtrue、そうでなければfalseを返す
  • all—すべてのイテラブルが真の場合はtrue、そうでなければfalseを返す
  • max—指定された繰り返し可能なコレクションの最大値を返す
  • min—指定された繰り返しなコレクションの最小値を返す
  • len—指定された繰り返しなコレクションの長さを返す
  • append—繰り返しなリストの末尾に値を追加

これらの関数の例を見てみます。

even_list = [2, 4, 6, 8, 10]

print(sum(even_list))
print(any(even_list))
print(max(even_list))
print(min(even_list))
even_list.append(14) # リストの最後に14を追加
print(even_list)
even_list.insert(0, 0) # 0と指定インデックス[0]を挿入
print(even_list)
print(all(even_list)) # リスト内のすべての要素がtrueの場合のみtrueを返す
print(len(even_list)) # リストのサイズを表示

この出力は以下のようになります。

30
True
10
2
[2, 4, 6, 8, 10, 14]
[0, 2, 4, 6, 8, 10, 14]
False
7

上の例では、append関数がリストの最後に1つのパラメータ(14)を追加しています。insert関数では、挿入するインデックスを指定できるため、even_list.insert(0, 0)0をインデックス[0]に挿入します。
リストには0の値があり、falseと判断されるため、print(all(even_list))falseを返します。最後に、print(len(even_list))がイテラブルの長さを出力します。

イテラブルの操作に役立つ高度な機能

Pythonには、イテラブルの操作を簡素化する高度な機能が組み込まれています。以下、いくつかご紹介します。

1. リスト内包表記

リスト内包表記を使用すると、既存のリストの各要素に関数を適用し、新規リストを作成できます。

my_numbers = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
even_number_list = [num for num in my_numbers if num%2 == 0]
print(even_number_list)

上の例では、11から20までの整数でmy_numbers というリストを作成します。偶数の整数だけを含む新たなeven_number_listを作成することが目的で、これを実現するには、my_numbersから整数を返すリスト内包表記を、その整数が偶数の場合にのみ適用します。if文には、偶数を返すロジックが含まれています。

この出力は以下のようになります。

[12, 14, 16, 18, 20]

2. zip関数

zip関数は、複数のイテラブルをタプルで返します。タプルは1つの変数に複数の値を格納し、変更不可能なデータ型です。例えば以下のようになります。

fruits = ["りんご", "オレンジ", "バナナ"]
rating = [1, 2, 3]

fruits_rating = zip(rating, fruits)
print(list(fruits_rating))

fruits_rating関数が、各評価と果物をペアにして、1つのイテラブルを生成し、出力は以下のようになります。

[(1, 'りんご'), (2, 'オレンジ'), (3, 'バナナ')]

最初のリスト(fruits)が果物を表し、2つ目のリストが1から3までの評価を表し、さまざまな果物の評価システムとして機能します。

3. filter関数

filter関数も上級者向けで、関数とイテラブルの2つの引数を取得します。イテラブルの各要素に関数を適用し、trueを返す要素のみを含む別のイテラブルを返します。以下は、与えられた範囲内の整数値のリストをフィルタリングし、偶数値のみを返すfilter関数の例です。

def is_even(n):
    return n%2 == 0

nums_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_list = filter(is_even, nums_list)
print(list(even_list))

まずはis_even関数を定義し、渡された偶数を計算。次に、1から10までの整数値のリスト(nums_list)を作成し、別のリスト(even_list)を定義します。filter関数を使用して、ユーザー定義の関数を元のリストに適用し、偶数リストの要素のみを返します。この結果は以下のようになります。

[2, 4, 6, 8, 10]

4. map関数

filter()と同じように、map関数も反復可能なファイルと関数を引数に取りますが、最初のイテラブルを返すのではなく、最初のイテラブルから各要素に関数を適用した結果を含む別のイテラブルを返します。例えば、整数のリストを2乗するには、map()を使用します。

my_list = [2, 4, 6, 8, 10]
square_numbers = map(lambda x: x ** 2, my_list)
print(list(square_numbers))

上のコードでは、xはリストを走査し、2乗計算によって変換するイテレータです。map()は、元のリストとマッピング関数を引数に取ることで、この処理を実行します。出力は以下のとおりです。

[4, 16, 36, 64, 100]

5. sorted関数

sorted関数は、指定されたイテラブルを特定の順序(昇順または降順)で並び替え、リストとして返します。iterablereverse(任意)、key(任意)の最大3つのパラメータを受け取ります。reverseのデフォルトはFalseで、Trueに設定すると、項目は降順に並び替えられます。keyは、イテラブルの並び替え順を決める値を計算する関数で、デフォルトはNoneになります。

以下は、sorted関数をさまざまなイテラブルに適用する例です。

# set
py_set = {'e', 'a', 'u', 'o', 'i'}
print(sorted(py_set, reverse=True))

# dictionary
py_dict = {'e': 1, 'a': 2, 'u': 3, 'o': 4, 'i': 5}
print(sorted(py_dict, reverse=True))

# frozen set
frozen_set = frozenset(('e', 'a', 'u', 'o', 'i'))
print(sorted(frozen_set, reverse=True))

# string
string = "kinsta"
print(sorted(string))

# list
py_list = ['a', 'e', 'i', 'o', 'u']
print(py_list)

それぞれ次のような結果になります。

['u', 'o', 'i', 'e', 'a']
['u', 'o', 'i', 'e', 'a']
['u', 'o', 'i', 'e', 'a']
['a', 'i', 'k', 'n', 's', 't']
['a', 'e', 'i', 'o', 'u']

エッジケースなどの問題への対処方法

エッジケースには、さまざまな状況で直面する可能性があり、イテラブルを扱う際にもエッジケースの想定が必要です。以下、遭遇する可能性のあるいくつかの問題をご紹介します。

1. 空のイテラブル

イテラブルが空であるにもかかわらず、プログラミングロジックがそれを走査しようとすると、問題が発生することがあります。プログラムでこの問題に対処し、無駄な操作を回避することができます。以下は、if notを使ってリストが空かどうかを確認する例です。

fruits_list=[]
if not fruits_list:
    print("リストが空です")

結果は以下のようになります。

リストが空です

2. ネストされたイテラブル

Pythonは、入れ子になったイテラブルもサポートしています。例えば、以下のように肉、野菜、穀物のような食品カテゴリのリストが入れ子になった食品リストを作成することができます。

food_list = [["ケール", "ブロッコリー", "生姜"], ["牛肉", "鶏肉", "鮪"], ["大麦", "オーツ麦", "とうもろこし"]]
for inner_list in food_list:
    for food in inner_list:
        print(food)

上のコードでは、food_list変数に3つの入れ子になったリストがあり、異なる食品カテゴリを示しています。外側のループ(for inner_list in food_list:)は主リストを繰り返し、内側のループ(for food in inner_list:)は各入れ子リストを繰り返して、各食品項目を表示します。

ケール
ブロッコリー
生姜
牛肉
鶏肉
鮪
大麦
オーツ麦
とうもろこし

3. 例外処理

Pythonのイテラブルは、例外処理にも対応します。例えば、リストを繰り返し処理していると、IndexErrorに遭遇することがあります。このエラーは、イテラブルの境界を超える要素を参照しようとしていることを意味し、try-exceptブロックを使用して例外処理を行うことができます。

fruits_list = ["りんご", "マンゴー", "オレンジ", "なし"]
try:
    print(fruits_list[5])
except IndexError:
    print("指定されたインデックスが範囲外です。")

上のコードのfruits_listには、リストコレクション内のインデックス0から5によってマップされた5つの要素が含まれています。tryにはprint関数が含まれ、イテラブルのインデックス5 にある値を表示しようとしますが、存在しません。そのため、exceptを実行して関連するエラーメッセージを返します。

指定されたインデックスが範囲外です。

まとめ

Pythonの反復処理をマスターすれば、効率的で読みやすいコードを書けるようになります。様々なデータ構造を反復処理する方法を理解し、内包表記やジェネレーター式を用いて、組み込み関数を活用することで、Pythonプログラマーとしての腕を上げることができます。

リスト、辞書、文字列、カスタムオブジェクトのいずれを扱うにせよ、反復処理の方法を学ぶことは、Pythonプログラマーの必須スキルです。

Pythonアプリを構築したら、Kinstaのアプリケーションホスティングでデプロイしませんか?初月の20ドル分は無料でご利用いただけるため、リスクなしでお試しいただけます。

Pythonの反復処理に関してご質問があれば、以下のコメント欄でお知らせください。

Jeremy Holcombe Kinsta

Content & Marketing Editor at Kinsta, WordPress Web Developer, and Content Writer. Outside of all things WordPress, I enjoy the beach, golf, and movies. I also have tall people problems ;).