Pythonにおけるfor文および関連する基本構文について

この記事を書いた人
北爪 聖也

株式会社pipon代表取締役。 キャリアはADK(広告代理店)でテレビ広告運用をして残業120時間するが、ネット広告では自分の業務がAIで自動化されていることに驚愕する。そこで、機械学習受託会社に転職し、技術力を身につけた後、piponを創業。現在、製薬業界、大手監査法人、EC業界、様々な業界でAI受託開発事業を運営。

公開日:2019/9/19
更新日:2019/9/19
キーワード:Python for文 基本構文
文字数:4700(読み終わるまでおよそ8分)

この記事でわかること

  • for文とは
  • for文と関連する基本構文

はじめに

プログラミングの基本は「条件分岐」と「繰り返し」の制御構造で、データサイエンスの世界でよく使われるプログラミング言語であるPythonにおいても、例外ではありません。

Pythonでは、繰り返しにはfor文または while文を、条件分岐にはif文を使います。

プログラミングの初心者にとっては、for文が難しいと思いますので、今回はfor文および関連する基本的な構文を見ていきます。

1. 制御構造における基本構文

パンダの中のパンダさんによる写真ACからの写真

1) for文とは

for文は、指定した回数だけ処理を繰り返したり、タプルやリストから値を順番に取り出したりする、ループ処理で使う構文です。

Pythonでは他のプログラム言語と違い、インデント(字下げ)を使ってfor文のブロックを解釈するので、注意が必要です。

本稿では、インデントは半角4文字で設定することとします。

<例文1-1>

country = ["Japan", "China", "US", "India"]
for name in country:
    print(name)
Japan
China
US
India

このコードでは、リストcountryに入っている国を、順番に取り出しています。

この機能を使って、指定回数だけ繰り返し処理を行うコードに活用します。ここで問題になるのが、処理を繰り返す回数をどう指定するかですが、range関数を使うことで実現できます。

n回処理を繰り返すには、次の書式のようになります。

for i in range(n):
    #インデントの開始(半角4文字下げ)
    ステートメント1
    ステートメント2
    ステートメント3
#インデントの終了(for文の終了)

この流れを図にすると、次のように表せます(図1)。

図1. for文の流れ

変数iには、繰り返しごとに0, 1, 2, …, n-1の数値が入ります。0からn回繰り返すので、最後の値がn-1になることに注意が必要です。

実際のコードの例を、例文1-2に示します。

<例文1-2>

for i in range(10):
    print(i)
0
1
2
3
4
5
6
7
8
9

変数iの値を出力するprint(i)を10回繰り返していることが、分かります。

2) range関数について

さて、for文を作成する際、処理の繰り返し数を指定するのに、range関数を用いました(例文1-2)。

ここでは、range関数について詳しく見ていきます。

他のプログラミング言語を学んだ方であれば、例文1-2の変数iは繰り返し数を数えるカウンタと思われるかと思いますが、Pythonでは少し考え方が違っており、range(10)が作った0~9の連続した数値から値を一つずつ取り出して、iに代入しています。

range関数は、連続した数字のオブジェクトを作るための関数で、次のような書式を持っています。

range(開始値,終了値,ステップ)

開始値を省略すると0、ステップを省略すると1になります。

従って、先ほどfor文で用いたrange(10)を省略しないで書くと、range(0, 10, 1)ということになります。

例文1-2のrange(10)をrange(6,10)とすれば、6~9の値が出力されます(例文2-1)。出力される値は、6~10ではないことに注意してください。

<例文2-1>

for i in range(6, 10):
    print(i)
6
7
8
9

range関数のステップを変えると、1個飛ばし(例文2-2)や逆順(例文2-3)の取り出しが可能となります。

<例文2-2>

for i in range(0, 10, 2):
    print(i)
0
2
4
6
8

<例文2-3>

for i in range(10, 0, -1):
    print(i)
10
9
8
7
6
5
4
3
2
1

ステップにマイナスの値を使って逆順に取り出す場合は、開始値と終了値を逆にすることを忘れないようにしてください。

3) for文とif文を使った複雑な条件分岐

以前、条件で処理を分岐させるときは、if文を使うことを述べました。

今回は、for文とif文を組合せて、少し複雑な条件分岐の作り方を見ていきます。

例文3-1は、0~9の数値の内、偶数ならそのままリストに追加し、奇数なら「奇数」という文字をリストに追加するコードです。

<例文3-1>

even_list = [] #空のリストを作る
for i in range(10):
    if i % 2 == 0:
        even_list.append(i) #2で割ったときの余りが0(つまり、偶数)なら、リストの最後に数値を追加する
    else:
        even_list.append("奇数") #奇数なら、「奇数」という文字をリストの最後に追加する
print(even_list)
[0, '奇数', 2, '奇数', 4, '奇数', 6, '奇数', 8, '奇数']

for文とif文を組み合わせることにより、for文の1回の繰り返しの中で、if-else文により条件の分岐処理を行い、それを規定の回数だけ繰り返す、といった処理が可能となります。

4) continueを用いた繰り返し処理のスキップ

for文の中でcontinueを実行することで、今の繰り返しを中断して、次の繰り返しに移る処理が可能となります。

continueを使ったfor文の流れを、図2に示します。

図2. continueを使ったときのfor文の流れ

continueを使ったときのfor文の例を、例文4-1に示します。

数値と文字が混在したリストがあり、文字は飛ばして数値だけ足し算するコードです。

<例文4-1>

number = [2, 5.4, "a", 10, 1, "b", 20]
sum = 0
for num in number:
    if not isinstance(num, (int, float)):
        print(num, "数値ではありません")
        continue
    sum += num
    print(num, "/", sum)
2 / 2
5.4 / 7.4
a 数値ではありません
10 / 17.4
1 / 18.4
b 数値ではありません
20 / 38.4

7つの数値または、文字を含むリストから順番に要素を取り出し、数値であれば数値と累積の合計値を示し、文字であれば、数値でないことを表示して、次の要素を取り出します。

文字列の”a”と”b”を取り出した後も、繰り返しを続けているのが分かります。

5) 複数のリストを組み合わせるzip関数

zip関数を使うと、for文で複数のリストを同時に扱うことができます。

例文5-1では、lnameとfnameのリストから順番に要素を取り出して、連結してfullnameを作っています。

lnameから取り出した要素はn1に、fnameから取り出した要素はn2に格納されます。リストの長さが異なる場合は、最も短いリストに合わせて処理は終了します。

<例文5-1>

lname = ["安倍", "山口", "枝野", "玉木", "松井"]
fname = ["晋三", "那津男", "幸男", "雄一郎", "一郎"]
fullname = []

for n1, n2 in zip(lname, fname):
    fullname.append(n1+n2)
print(fullname)
['安倍晋三', '山口那津男', '枝野幸男', '玉木雄一郎', '松井一郎']

6) enumerate関数でリストの要素とカウンタの値を取得

enumerate関数を用いることで、for文のループカウンタの値を、リストから取り出した要素と合わせて、変数に取り出すことができます。

例文6-1では、iにカウンタの値が入り、nameにlistから取り出した要素が格納されます。カウンタの値は指定しなければ0からですが、例文のように開始値を指定することもできます。

<例文6-1>

list = ["安倍", "山口", "枝野", "玉木", "松井"]
for i, name in enumerate(list, 1):
    print(f"{i}: {name}さん")
1: 安倍さん
2: 山口さん
3: 枝野さん
4: 玉木さん
5: 松井さん

7) reverse関数でリストの要素を逆順で取得

リストの要素を逆順に取り出したい場合、リストの要素をreverse関数で逆順に並べ替えてから、先頭から順番に取り出す方法があります(例文7-1)。

リストに対してreverse関数を用いると、新しいリストを作るのではなく、元のリストの値を並び変えてしまうので注意してください。

元のリストはそのままにして、要素を逆順に取り出したい場合は例文7-2のように書けば問題ありません。

<例文7-1>

list = ["安倍", "山口", "枝野", "玉木", "松井"]
list.reverse()
for i in list:
    print(f"{i}さん")
松井さん
玉木さん
枝野さん
山口さん
安倍さん

<例文7-2>

list = ["安倍", "山口", "枝野", "玉木", "松井"]
for i in list[::-1]:
    print(f"{i}さん")
    
print(list) #元のリストを確認
松井さん
玉木さん
枝野さん
山口さん
安倍さん
['安倍', '山口', '枝野', '玉木', '松井']

8) リスト内包表記

リスト内包表記は、他のプログラミング言語では見られない、Pythonらしい記述方法の一つで、以下の書式で表せます。

[for 変数 in 要素]

コードの可読性は低下してしまうものの、append関数を呼び出さないため、実行速度が速いというメリットがあります(例文8-1)。

<例文8-1>

num_list = [1, 2, 3, 4, 5]
num_double = [num*2 for num in num_list]

print(num_double)
[2, 4, 6, 8, 10]

例文8-1を、リスト内包表記を使わずに書くと、例文8-2のように書けます。

<例文8-2>

num_list = [1, 2, 3, 4, 5]
num_double = []
for num in num_list:
    num_double.append(num*2)

print(num_double)
[2, 4, 6, 8, 10]

内包表記には条件式を入れることもでき、例えば例文3-1をリスト内包表記を使って書くと、とてもシンプルに書けます(例文8-3)。

<例文8-3>

even_list = [i if i % 2 == 0 else "奇数" for i in range(10)]

print(even_list)
[0, '奇数', 2, '奇数', 4, '奇数', 6, '奇数', 8, '奇数']

内包表記は非常にシンプルにコードを書けますが、初心者には分かりにくい表記なので、Pythonに慣れないうちは、内包表記を使わないコードを書くとよいと思います。

2. おわりに

今回は、Pythonの構文の中でも初心者がつまづきやすい、for文および関連する基本構文について述べました。

データ解析の際は、条件に合うデータのみデータベースから取り出すというように、条件分岐と繰り返しを使って、解析用のデータベースを作成したい場面が出てきます。

今回述べたfor文は、繰り返し処理の基本となる構文なので、しっかり理解しておいてください。

3. 参考サイト

リスト内包表記とif文を組み合わせるとき
https://qiita.com/kokorinosoba/items/eb72dac6b68fccbac04d

Python入門〜for文、if文を使って条件処理をする〜
https://to-kei.net/python/intro2/#forif