for文で処理を繰り返し実行する際の典型的なコード例を紹介。range関数、enumerate関数、zip関数、break文とcontinue文についても触れる。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
# 基本形
iterable = ['a', 'b', 'c']
for item in iterable: # for <ループ変数> in <反復可能オブジェクト>:
print(item) # <ループ変数>を使った処理:'a'、'b'、'c'を順次出力
# 指定した回数だけ処理を繰り返す:range関数
for counter in range(5):
print(counter) # 0、1、2、3、4を順次出力
# インデックスと要素を扱いたい場合:enumerate関数
for index, item in enumerate(iterable):
print(index, ':', item) # '0 : a'、'1 : b'、'2 : c'を出力
# 複数の反復可能オブジェクトをまとめる:zip関数
code_point = [ord(c) for c in iterable] # [97, 98, 99]
for c, p in zip(iterable, code_point):
print(f'{c} : {p}') # 'a : 97'、'b : 98'、'c : 99'を順次表示
# ループの脱出:break文
for num in iterable:
if num == 'b': # <ループ変数>の値が'b'なら最内のループを脱出
break
print(num) # 'a'を出力してループを終了
# ループの継続:continue文
for num in iterable:
if num == 'b': # <ループ変数>の値が'b'なら以降の処理を省略してループを継続
continue
print(num) # 'a'、'c'を出力('b'は出力されない)
for文の構文を以下に示す。なお、for文の詳細については「Python入門」の「for文による繰り返し処理」「リストと繰り返し処理」なども参照されたい。
for <ループ変数> in <反復可能オブジェクト>:
<ループ変数>を使用する処理
else:
break文でループを脱出していない場合の終了処理
<反復可能オブジェクト>とは、それが格納している要素を反復的に取り出せるオブジェクトのこと。代表的な例としては、リストやタプル、集合、辞書などがそうだ。あるいは、反復可能オブジェクトの代わりに、イテレータのような反復的に値を返送可能なオブジェクトを置くことも可能だ(実際、以下で紹介するenumerate関数とzip関数はイテレータを戻り値とする)。
for文では、そのブロックに記述された「<ループ変数>を使用する処理」を、<反復可能オブジェクト>の要素が尽きるまで繰り返し実行する。コードの実行時には、<ループ変数>に指定した変数に、<反復可能オブジェクト>の要素が1つずつ代入されていく。C系統の言語のfor文とは異なり、Pythonのfor文は反復可能オブジェクトの要素に対して、反復的に処理を行うためのものであることには注意しよう。
ループが終了した時点で実行したい処理があれば、for文のelse節にそれを書くこともできる(省略可)。ただし、使うことはそれほど多くはないだろう。注意する点としては、break文(後述)でループを脱出したときには、else節に書いたコードは実行されないことが挙げられる。
Pythonのfor文は反復可能オブジェクトの要素を反復的に処理するものだが、指定した回数だけ処理を繰り返すこともできる。これには<反復可能オブジェクト>の位置にrange関数呼び出しを置けばよい。
range関数は引数に指定した初期値(start)/最終値(stop)/増分値(step)を使って、「初期値+増分値×n」で表現される等差数列(範囲は初期値から最終値)に含まれる値を反復するrangeオブジェクトを戻り値とする。以下に構文を示す。
range(stop)
range(start, stop[, step])
最終値に指定する値はその数列には含まれないので注意すること。例えば、初期値=2、最終値=8、増分値=2を指定した場合(range(2, 8, 2)呼び出し)では、2、4、6を反復するrangeオブジェクトが得られる(最終値は8だが、これはrangeオブジェクトが反復する値の範囲には含まれず、増分値が2なので7も含まれず、6がこのオブジェクトが表す数列の最後の値となる)。
最も簡単な使い方は最終値(stop)のみをrange関数に指定するもので、この場合は初期値は0で、増分値に1を指定したものと見なされる(つまり、0から最終値−1の範囲の整数が順番に取り出される)。
2つの値をrange関数に渡した場合には、初期値(start)と最終値(stop)を指定することになり、増分値(step)は1となる。3つの値をrange関数に渡した場合には、初期値(start)/最終値(stop)/増分値(step)の全てが指定される。なお、増分値に負値を指定することも可能だ(このときには、初期値から最終値へと、値が減っていく数列となる)。
以下に例を示す。
# 最終値のみを指定(初期値は0、増分値は1)
for num in range(3):
print(num) # 0、1、2
# 初期値と最終値を指定(増分値は1)
for num in range(2, 5):
print(num) # 2、3、4
# 初期値と最終値と増分値を指定
for num in range(2, 8, 2):
print(num) # 2、4、6
# 増分値に負値を指定
for num in range(5, 2, -1):
print(num) # 5、4、3
「解決!Python」の「文字列やリストの要素数を調べるには」でも触れたが、for文で反復可能オブジェクトの要素と、それに対応するインデックスを同時に扱いたいときには、enumerate関数と組み合わせる。enumerate関数に反復可能オブジェクトを渡すと、その要素と対応するインデックスを「(インデックス, 要素)」というタプルで反復してくれるenumerateオブジェクトが得られる。
enumerateオブジェクトを2要素のタプルを反復するので、ループ変数ではそれらをタプルで受け取るのが簡単だ。1つの変数で受け取って、インデックスアクセスをすることは可能であり、その場合はタプルの最初の要素がインデックス値で、次の要素が反復された要素となる(が、以下のコード例に示すようにタプルの要素にアクセスするのが面倒なので、使うことはあまりないと思われる)。
なお、enumerate関数では第2引数でインデックスの初期値を指定できる。
以下に例を示す。
iterable = [chr(num+ord('A')) for num in range(3)]
# (インデックス, 要素)を個別のループ変数に代入
for index, item in enumerate(iterable):
print(index, ':', item) # '0 : A'、'1 : B'、'2 : C'
# (インデックス, 要素)を単一のループ変数に代入
for t in enumerate(iterable):
print(t[0], ':', t[1]) # '0 : A'、'1 : B'、'2 : C'
# インデックスの初期値を1にする
for index, item in enumerate(iterable, 1):
print(index, ':', item) # '1 : A'、'2 : B'、'3 : B'
関連のある値を含んだ反復可能オブジェクトが複数あり、それらをfor文でまとめて処理したいという場合には、zip関数が使える。zip関数は、1つ以上の反復可能オブジェクトをパラメーターに受け取り、それらの同じインデックス位置にある要素で構成されるタプルを反復するイテレータを戻り値とする。
例えば、X座標を要素とするリストと、Y座標を要素とするリストがあり、それらは同じインデックス位置にある要素同士が組みになっているとする。それらのX座標/Y座標の組を串刺し的に扱うのにzip関数が使用できる。以下に例を示す。
x = list(range(5)) # [0, 1, 2, 3, 4]
y = list(range(1, 6)) # [1, 2, 3, 4, 5]
# タプルを単一のループ変数に受け取る例
for coord in zip(x, y):
print(coord) # (0, 1)、(1, 2)、(2, 3)、(3, 4)、(4, 5)
# タプルの要素を個別のループ変数に受け取る例
for xp, yp in zip(x, y):
print(f'({xp}, {yp})') # (0, 1)、(1, 2)、(2, 3)、(3, 4)、(4, 5)
# タプルの内容を基に辞書を作り、それらを要素とするリストを作る
xy_list = [] # 空のリスト
for xp, yp in zip(x, y):
xy_list.append({'x': xp, 'y': yp})
最後の例は、X座標とY座標から辞書を作成し、それらを要素とするリストとしているが、学籍番号順に並べられた名前だけのリスト、数学のテストの点だけを集めたリスト、物理のテストの点だけを集めたリスト、……があったときに、それらから個人の名前とテスト結果をまとめたデータ構造を作るといったときにも利用できるだろう。
なお、反復可能オブジェクトの要素数が一致していない場合には、要素数が一番短いものに合わせられて、余った要素については無視される。
何らかの条件が成立した場合、for文での処理を中断するにはbreak文を使用する。これは現在実行しているループの中で最も内側のものを中断させる。break文が実行されたときには対応するfor文のelse節は実行されない。以下に例を示す。
iterable = list(range(5)) # [0, 1, 2, 3, 4]
for num in iterable:
if num == 3: # ループ変数numの値が3ならそこで処理を中断
break
print(num)
x = list(range(1, 10))
y = list(range(1, 10))
limit = 5
result = []
for num1 in x:
if num1 > limit: # 外側のループ変数num1がlimitより大きくなったら
break # 外側のforループを終了
tmp = []
for num2 in y:
if num2 > limit: # 内側のループ変数num2がlimitより大きくなったら
break # 内側のforループを終了
tmp.append(num1 * num2)
result.append(tmp)
for cnt, item in enumerate(result, 1):
print(f'{cnt}の段: {item}')
2つ目の例は、二重のforループで九九を計算するものだが、無理やりにbreak文を使うような構造とした(サンプルなのでご容赦願いたい。九九の計算ならもっとシンプルに書けるはずだ)。外側/内側のforループでは、どちらも変数limitの値を参照して、そこで指定された値になったらループを中断するようになっている(実行結果は省略)。
break文と異なり、ループ時に特定の条件が成立したら、以降の処理は省略して、次のループを開始する(継続する)のに使用できるのがcontinue文だ。以下に例を示す。
for num in range(10):
if num % 2: # ループ変数numの値が奇数なら
continue # 以降の処理を省略して、ループを継続
print(f'{num}: even')
上のコード例は、ループ変数の値を2で割った余りが1ならcontinue文が実行される。このときには、その下のprint関数呼び出しは省略されて、numには次の値が代入されて、ループが継続される。つまり、ループ変数numの値が奇数であれば、何も出力されず、偶数の場合には、その値と偶数であることが表示される。
Copyright© Digital Advantage Corp. All Rights Reserved.