- pythonのfor文の実装方法
- continue, breakを用いてループを飛ばす、強制終了させる
- elseを用いてループ後に特定の処理を実行
- enumerateでインデックスも同時に取得
- zipで複数の要素を同時にループ
- reversedで逆順にループ
- Iterableとは何か、そもそもなぜforでループできるのか言語仕様
について、必要十分なだけ、詳細に説明します。
[rtoc_mokuji title="" title_display="" heading="h3" list_h2_type="" list_h3_type="" display="" frame_design="" animation=""]
基本的な使い方(list, 文字列、タプル(set)、セット(tuple)への使用)
forループを使用するには、そのクラスがIterableである必要がある。
・Iterableなクラスの例
・Iterableなクラスの実行できる関数の例
| 関数名 | 処理内容 | 
|---|---|
| list, tuple, dict, set | list, tuple, 辞書, set型に型変換する | 
| sum | 中身の合計値を計算する | 
| sorted | 昇順に並べ替える | 
| any | リストなどの中のオブジェクトの1つでもbool(object)の結果がTrueの場合True | 
| all | リストなどの中のオブジェクトの全てのbool(object)の結果がTrueの場合True | 
| max | 最大値を求める | 
| min | 最小値を求める | 
- for でループする方法
<statement(s)>
ループにて、オブジェクトの種類によって返される値は異なります。
↓ 色んな型をループした例
Example
- list型のオブジェクトをforループする場合、listの中身が1つずつ取り出される
print(f)
# apple
# grape
# lemonを表示
- 文字列型をforループする場合、文字が1文字ずつ取り出される
print(m)
# h
# e
# l
# l
# o
# を表示
- タプル型をforループする場合、中身が1つずつ取り出される
print(f)
# apple
# grape
# lemon
# を表示
- セット型をforループする場合、セットは順番が決まっていないため順番がバラバラになる
print(f)
# apple, grape, lemonを順不同で表示
このとき、インデックス(0, 1, 2...)も一緒に取り出したい場合、enumerate関数を用いる。
このように、Iterableなオブジェクトはそれぞれ、取り出される形式はそれぞれ異なる。
これは、各クラスの内部でどのように値を返すのか、その実装方法が異なるからです。
最後のIterableのオブジェクトの実装方法で記載する。
rangeを使用した数字のループ
iを0から9までループすることができる。
pythonの場合、以下のように書いても同じことができるが、もっとシンプルなやり方が推奨されいている
それは、range関数を用いる方法
range関数は、数値の連番を返すIterableなオブジェクトを返す
例えば、range(<end>)は、0からend未満までの数値を順に返す
Example
- rangeの基本的な使い方
ran # range(0, 5)
type(ran) # <class 'range'>
for x in ran:
print(x)
# 0, 1, 2, 3, 4を表示する
rangeが返す値は。リストでもタプルでもなく。rangeクラスのインスタンスで、Iterable(反復可能)な型。
rangeをリストやタプルに変換するには、以下のようにlist関数、tuple関数を用いる
Example
- rangeクラスのインスタンスをlist, tupleに変換
list(x) # list型[0, 1, 2, 3, 4]
tuple(x) # tuple型(0, 1, 2, 3, 4)
range(<begin>, <end>, <stride>)と指定した場合
begin以上end未満の値を返す。
strideはスキップする値を指定する。(デフォルトは1なので、省略すると1になる。)
具体的には以下のように使用する。
Example
- 特定の値をスキップして、取り出す例
print(x) # 2, 3, 4, 5が表示される
for x in range(2, 10, 3):  # 2以上10未満、スキップは3
    print(x) # 2, 5, 8が表示される
また、スキップする値にマイナスを指定することができ、マイナスを指定すると逆順に数値を取り出すことができる。
Example
- rangeのスキップする値にマイナスを指定した場合
print(i)
# 10 9 8 7 ... 2まで順に表示
for i in range(20, 2, -4):# 20で始まって2まで(2を除く)-4スキップしてループ
    print(i) # 20 16 12 8 4 が表示される
以上、rangeでループすることは鉄板なので、覚えておきましょう!
辞書(dict)のforループ
ただし、python3.6以前は、辞書のキーの順番は保持していない。つまり順不同で取り出されるため注意が必要。
Example
- 辞書型のループ(基本的な使い方)
for k in dict_a:
print(k)
# foo
# fiz
# baz
# を表示
- 辞書のキーをループして、それを元の辞書で取り出すキーに指定する場合
for k in dict_a:
print(dict_a[k]) # またはprint(dict_a.get(k))
# 1
# 2
# 3
# を表示
として、辞書から値を取り出すことができます。
あるいは、辞書型の値を取り出すメソッド、valuesメソッドを使用しても同じように辞書から値を取り出すことができます。
Example
- valuesメソッドを用いて値を取り出す場合
type(dict_a.values()) # dict_valuesクラス
for v in dict_a.values():
print(v)
# 1
# 2
# 3
# を表示
辞書型から、キーと値を同時に取り出すこともできる
Example
- itemsメソッドで、キーと値を同時に取り出す場合
type(dict_a.items()) # dict_itemsクラス
# kに辞書のキー、foo, fiz, bazが入り
# vに辞書の値、1, 2, 3が入る
for k, v in dict_a.items():
print(k, v)
# foo 1
# fiz 2
# baz 3
# を表示
このように、辞書型からforループで、キーを取り出す。値を取り出す。キーと値を取り出すなどができる
forループ内でのcontinue, breakの使用
continueというのは、forループ文中に仕込んで、ループ処理の途中で処理を中断して次のループに進める機能のことを言う
例えば、
以下のように記述すると、iが3のときだけ飛ばされて、print(i)が実行されず、3がターミナル上に表示されない。
Example
- continueを使った書き方(i==3でcontinue)
if i == 3: # iが3の場合
continue # continueで次のループ(i=4)に飛ばされる
print(i) # i=3の時だけ実行されないため、0 1 2 4を表示
breakの場合には、forループそのものを終了してループの外に出てしまう。
以下の例では、i=3でbreakが実行されてループの外に出ることになり、i=3とi=4のときに、print(i)が実行されない
Example
- breakを使った書き方(i==3でbreak)
if i == 3: # iが3の場合
break# breakでループの外に出る
print(i) # i=3でループの外に出るため、i=3,4の時だけ実行されない
# 0 1 2 4を表示
以上、forループ文内での、continueとbreakの書き方でした!
elseを用いて、ループ終了後に処理を実行
次に、elseを使用してforループ処理後に何らかの処理を行う方法について詳述する
とは言え、これは使う非常に機会は少ない。。
(Effective Pythonなどの本ではこのやり方は非推奨にされています。)
以下のように記述すると、forループの終了後に、else内で記述した処理を実行してくれる。
Example
- elseを利用した例
pass # 何らかの処理を記述
else:
print('ループ終了')
# forループ終了後に実行され、「ループ終了」とprintされる
ただし、breakが実行されてforループの外に出た場合には、elseの中の処理は実行されない
Example
- breakを使用した場合のelse
print(i)
if i == 3:
break
else:
print('ループ終了') # i==3でbreakが実行されてしまうため、この処理は実行されない
2次元配列の値を複数取得してループする
list_a = [[1, 2], [3, 4], [5, 6]]
この(1, 2), (3, 4), (5, 6)を、組み合わせで取得してループする。
それには、forの引数を複数指定すればよい。
Example
- 2次元配列を同時にループする例
for x in list_a:# xには、[1, 2] [3, 4] [5, 6]が配列として格納される
print(x)
# [1, 2]
# [3, 4]
# [5, 6]
# xには、1 3 5。 yには、2 4 6が格納される
for x, y in list_a:
    print(x, y)
    # 1 2
    # 3 4
    # 5 6
list_a = [[1, 2, 'A'], [3, 4, 'B'], [5, 6, 'C']]
for x, y, z in list_a:
    print(x, y, z)
    # 1 2 A
    # 3 4 B
    # 5 6 C
enumerateを用いたインデックスの取得
次に、インデックスを同時に取得するやり方について説明する。
例えば以下の場合、リストの中の値とそのインデックス(0番目、1番目、2番目...)を取得したい場合がある。
この場合、enumerateを用いる
Example
- enumerateを使用しないfor文
for x in list_a: # 普通のやり方では、xにapple, banana, lemonが入る
print(x) # apple, banana, lemonを表示される
- enumerateを使用したfor文
for i, x in enumerate(list_a):# インデックスも同時に取得する。xにapple, banana, lemonが入り、iに0, 1, 2が入る
print(i, x) # 0 apple, 1 banana, 2 lemonが表示される
enumerateでインデックスを特定の値からカウントアップしたい。
例えば、0 1 2のようにカウントアップするのでなく、1 2 3のようにカウントアップしたい場合
enumerateの第2引数に、1を入れることでできる
Example
- enumerateで、1からカウントアップする
for i, x in enumerate(list_a, 1):# 1始まりでインデックスを取得(enumerateの第2引数が2の場合2から始まってカウントアップする)
print(i, x) # 1 apple, 2 banana, 3 lemonを表示
zipを用いて、複数のオブジェクトを同時にループ
複数のリスト、辞書などを同時にループしたい場合、zip関数を使うとよい
Example
- zipを利用して同時にループ
list_b = ['D', 'E', 'F']
list_c = ['G', 'H', 'I']
# list_aとlist_bとlist_cを同時にループ
for x, y, z in zip(list_a, list_b, list_c):# xにA, B, Cを格納し、yにD, E, Fを格納し、zにG, H, Iを格納する
print(x, y, z)
# A D G
# B E H
# C F I
# を表示
このように、zipを使用すると複数のIterableなオブジェクトをループさせることができる
ここで、オブジェクトの長さが違う場合、どうなるでしょうか?
長さが違う場合には、一番長さが小さいものに合わせる。
Example
- 長さが違うものをzipでループ
list_b = ['a', 'b', 'c', 'd']
list_c = ['1', '2']
# list_aは長さが3, list_bは長さが4, list_cは長さが2なので
# 最も長さの小さい2に合わせて、xには、A, B。yには、a, b。zには、1, 2が入る
for x, y, z in zip(list_a, list_b, list_c):
    print(x, y, z)
    # A a 1
    # B b 2
    # が表示される
zipを利用すると、2次元のタプルを作成することもできる
Example
- zipを使って、2次元のタプルを作成する例
list_b = ['a', 'b', 'c', 'd']
list_c = ['1', '2']
x = tuple(zip(list_a, list_b, list_c)) # xには、(('A', 'a', '1'), ('B', 'b', '2'))が格納される
x = list(zip(list_a, list_b, list_c)) # xには、[('A', 'a', '1'), ('B', 'b', '2')]が格納される(リストの中にタプル)
reversedを用いて、複数のオブジェクトを同時にループ
- reversedを用いて、ループの順番を逆にする
Example
- reversedを用いて、ループの順番を逆にする(# 文字列型)
- reversedを用いて、ループの順番を逆にする(# タプル)
list(reversed(x)) # ['n', 'o', 'h', 't', 'y', 'p']
- reversedを用いて、ループの順番を逆にする(# Range)
list(reversed(x)) # 8, 7, 6, 5, 4, 3, 2
- reversedを用いて、ループの順番を逆にする(# リスト)
list(reversed(x)) # 5, 4, 3, 2, 1
- reversedを用いて、ループの順番を逆にする(# 辞書型)
x = {'A': 1, 'B': 2, 'C': 3}
list(reversed(x)) # ['C', 'B', 'A']
このように、reversedを用いると逆順に並び替えることができる
また、enumerateやzipを組み合わせた場合、以下のように色んなパターンでループさせることができる
- reversedとenumerateとzipを組み合わせる
Example
- 逆順にしたリストにインデックスを付ける(reversed → enumerate)
# list_aを逆順にしてインデックスを付ける
# iには0 1 2が入り、xにはlemon, grape, appleが入る
for i, x in enumerate(reversed(list_a)):
    print(i, x)
    # 0 lemon
    # 1 grape
    # 2 apple
- インデックスを付けたリストを逆順にする(enumerate → reversed)
for i, x in reversed(list(enumerate(list_a))):
print(i, x)
# 2 lemon
# 1 grape
# 0 apple
- 2つのリストを合わせて両方逆順にする(zip → reversed)
list_b = ['D', 'E', 'F']
# list_a, list_bを合体させたものを逆順
for x, y in reversed(list(zip(list_a, list_b))):
print(x, y)
# C F
# B E
# A D
- 逆順のリストとそのままのリストを合体してループ(reversed → zip)
list_b = ['D', 'E', 'F']
# list_aの逆順, list_bを合体
for x, y in zip(reversed(list_a), list_b):
print(x, y)
# C D
# B E
# A F
Iterableなオブジェクトの作成(forループの仕様詳細)
Example
- Iterator作成の例(iterとnext)
it = iter(list_a)
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
print(next(it)) # Error(StopIteration)
このIteratorの作成(iter関数)、nextでの値の取得、StopIterationがforループを理解する上での鍵となる
print(x)
内部的には、以下のような動きになっています。
- list_aのイテレータを作成(iter関数を実行)
- 1で作成したイテレータから要素を取り出す(next関数の実行)
- StopIterationを検知したら処理を終了(forループの外に出る)
 
ここで、Iterableなオブジェクトには、iter関数とnext関数が実行できて、StopIterationで処理を終了させる処理が実装されています。
では、iter関数とは何か?
iter関数は内部的には、__iter__というクラスの特殊メソッドを呼び出している
(特殊メソッドについてはこちらを参照)
同様に、next関数は、__next__という特殊メソッドを内部で呼び出している
つまり、__iter__, __next__を実装することで、Iterableなオブジェクトを作成できる。
(リスト、辞書、文字列などのクラスは、__iter__, __next__などが実装されており、Iterableなオブジェクトになる)
| 要素 | 概要 | 
|---|---|
| __iter__ | インスタンスを初期化して、Iteratorを返す | 
| __next__ | ループ時の次の値を返す。ループを終了させたいところでStopIterationをraiseする | 
| StopIteration | ループを終了させる | 

Example
- Iterator作成の例
# Iteratorを作成する。forのループの最初に自動実行
def __iter__(self):
self.a = 1
return self
    # 次の値を取り出す。forループの際にループ毎に実行
    def __next__(self):
        if self.a <= 10:
            x = self.a
            self.a += 1 # self.aに1を加算
            return x # x(self.aの現在の値を返す)
        else:
            # ループを終わらせる
            raise StopIteration
myclass = IterNumbers()
# ループする
# __iter__が呼び出され、__next__がループの度に呼ばれる
# xが10を超えたとき、StopIterationが返されループが終了
for x in myclass:
    print(x)# 1から10まで表示
上のように、__iter__, __next__を実装することで、ご自身のクラスをIterableにすることができる。
リスト、辞書などのクラスは、すでに__iter__, __next__が実装されていて、リストなら要素の中身を、辞書ならキーをそれぞれ__next__のなかで返す。
以上、長くなりましたが、forループについて詳細を説明しました。
 
           
           
          