Python/条件分岐と繰り返し

出典: フリー教科書『ウィキブックス(Wikibooks)』
ナビゲーションに移動 検索に移動



Python の制御構造には、逐次・分岐・繰返しの3つがあり。このうち逐次はプログラムが左上から左から右・上から下に進む当たり前の状態ですので、これ以上の説明は必要ないと思います[1]

条件分岐[編集]

条件分岐とは、ある条件を満たすかどうかで、次に実行するプログラムの位置を変えることです。

if文[編集]

最も素朴な条件分岐は、単一のif文です[2]

if文による条件分岐
x = 3

if x == 2 :
    print("abcd")
条件分岐の上のコードの、x == 2とは、「xは2に等しい」という意味です。
冒頭の「x = 3」は、xに3を代入するという意味です。
python では、if文にある条件式にある等号と、代入との等号を区別するために、条件分岐での等号にはx == 2を使います。
上のコードでは、「xは2に等しい」の条件を満たさないため(xには3が代入されています)、実行しても文「abcd」は表示されません。
また、pythonでは、if文の中の文(ブロックと言います)は、字下げをします(この様なインデントによる構造構文をオフサイドルールと言います)。
インデントは半角スペース4つが推奨されます。
実行結果

※なにも表示されません。


つぎに、if文のなかのxの条件を変えてみて、条件が成り立つようにしましょう。

条件が真になるように変更
x = 3

if x == 3 :
    print("abcd")
上のコードでは、「xは3に等しい」の条件を満たすので、実行したら文「abcd」が表示されます。
実行結果
abcd

つまり、if文の構文は、次のようになります。

if 条件式 :
    処理
if文のブロックの外に文を追加
x = 3

if x == 2 :
    print("abcd")
print("ef")

上のコードでは、print("ef")はif文のブロックの外にあることになります。 なぜなら、print("ef")は字下げされてないからです。 なので、プログラムを実行すると「ef」が表示されます。

いっぽう、次のコードでは、結果が変わります。

if文のブロックに文を追加
x = 3

if x == 2 :
    print("abcd")
    print("ef")

上のコードでは、print("ef")はif文ブロックの中にあるので、プログラムを実行しても、「ef」は表示されませんし、もちろん「abcd」も表示されません。

ifブロック内は、字下げをそろえないと、エラーになります。

インデントに誤りのある例
x = 3

if x == 2 :
    print("abcd")
   print("ef")

(↑エラーになります。)

下記コードでは、x==2が満たされていないので、インデントされたブロックは実行されません。そのため実行すると「プログラムが終了しました。」だけが表示されます。

x = 3

if x == 2 :
    print("abcd")
    print("ef")
print("プログラムが終了しました。")

条件式には、不等号(><など)も使えます。

x = 3

if x > 2 :
    print("xは2よりも大きい。")
print("プログラムが終了しました。")

上のコードを実行すると「xは2よりも大きいよ。」と「プログラムが終了しました。」が表示されます。

比較演算子[編集]

記号>のような、値を比較する演算子のことを比較演算子といいます。 pythonで使える比較演算子には、次の表のようなものがあります。

比較演算子
演算子 意味
> 左側の数が、右側の数よりも大きい
< 左側の数が、右側の数よりも小さい
== 両辺の数値の大きさが等しい
!= 等しくない
>= 左側の数が、右側の数よりも大きいか、
または両辺が等しい
<= 左側の数が、右側の数よりも小さいか、
または両辺が等しい

in 演算子[編集]

in 演算子は、オブジェクトがコレクションの要素にあるかを返します。

in 演算子
li = [2,3,5]
tu = (10,20,30)

print(2 in li)
print(2 in tu)
実行結果
True
False

else節のあるif文[編集]

前の節では、if文の条件式によってブロックの実行/否を切り替えました。 ここでは、一歩進めて条件式に合致していなかった場合に別のブロックを実行するelse節を含んだ条件実行構文を紹介します[3]

else節のあるif文
x = 3

if x == 2 :
    print("xは2に等しい。")
else :
    print("xは2に等しくありません。")
print("プログラムが終了しました。")
実行結果
xは2に等しくないよ。
プログラムが終了しました。

なお、elseをつかわないでも、同じ内容の処理が書けます。

else節を使わず、逆論理の別のif文を使った例
x = 3

if x == 2 :
    print("xは2に等しい。")
if x != 2 :
    print("xは2に等しくありません。")
print("プログラムが終了しました。")
2つの例は同じ動作をしますが、後者は「変更漏れの原因となる」という重大な欠点があるので、好んで逆論理のif文を使わずelseを使いましょ。

elif節のあるif文[編集]

else節を使うと、条件式によって2方向にプログラムフローを分けることができました。 実施のプログラムでは、2つ以上の条件式によってプログラムフローを分けることがあります。 そのような場合、次のように条件式ごとにif文が入れ子になります。

else節のあるif文
x = float("nan")

if x < 0 :
    print("xは0より小さい。")
else :
    if x > 0 :
        print("xは0より大きい。")
    else :
        if x == 0 :
            print("xは0と等しい。")
        else :
            print("xは", x)
print("プログラムが終了しました。")
実行結果
xはnan 
プログラムが終了しました。

このプログラムは意味的には正しいのですがインデントが深くなりすぎ、読むのも修正するのも難儀なので、Python にはelse節の中にif文が入れ子になっていことを表すキーワード elif が用意されています。

elifによる置換え
x = float("nan")

if x < 0 :
    print("xは0より小さい。")
elif x > 0 :
    print("xは0より大きい。")
elif x == 0 :
    print("xは0と等しい。")
else :
    print("xは", x)
print("プログラムが終了しました。")
実行結果
xはnan 
プログラムが終了しました。
インデントが深くなりすぎず読みやすいですね。

if 式[編集]

Python には、if文の他、if式があります。

コード例
x = 3

print("xは2に等しい。" if x == 2 else "xは2に等しくありません。")
print("プログラムが終了しました。")
実行結果
xは2に等しくありません。
プログラムが終了しました。
これで、else の例と同じ意味になります。
PerlRubyの後置のifと似ていますが else を伴うので、C言語系の条件演算子と(構文はまるで違いますが)機能的には同じです。
大概の場合、if文を使ったほうが読みやすいのですが、内包表記やラムダ式では式が要求されるので、if式を使う必要があります。
nanってナニ?
唐突に float("nan")、が出てきましたが、これがPythonでNaN(Not a Number; 非数)を得る方法で、他には math を import して math.nan を使う方法もあります。

nan は、浮動小数点演算の結果として、不正なオペランドを与えられたために生じた結果を表す値またはシンボルで[4]、NaNの体系的仕様は、無限大の表現などと共に1985年の IEEE 754 浮動小数点規格で標準が与えられています。

nanの特徴
どんな値と比較しても不一致
nan 自身とも一致しないです( nan == nan ⇒ False )
どんな数学関数の引数に与えても結果は nan
nan であるかは is 演算子をつかう( nan is nan ⇒ True)
あるいは math を import し math.isnan(x) をつかう( isnan(nan) ⇒ True)


論理演算子[編集]

「変数xは2より大きくて、5より小さい」ときにだけ実行するような処理は、次のように書きます。

x = 3

if x > 2 and x < 5 :
    print("xは2より大きくて5より小さい。")
else:
    print("そうでない場合。")
print("プログラムが終了しました。")

andは、両方の条件が成り立つという意味です。

上記のコードを実行すると、「

xは2より大きくて5より小さいよ。

」が表示されます。「そうでない場合。」は表示されません。


xを6に変えてみましょう。

x = 6

if x > 2 and x < 5 :
    print("xは2より大きくて5より小さい。")
else:
    print("そうでない場合。")
print("プログラムが終了しました。")

上記のコードを実行すると、「

そうでない場合。

」が表示されます。「xは2より大きくて5より小さいよ。」は表示されません。

演算子 andをもちいて、

if 条件式A and 条件式B :

のように、使いうことにより、条件式Aと条件式Bが両方とも成り立つ場合に、「条件式A and 条件式B」が成り立つという意味にできます(数理論理学の用語でいう「論理積」です)。

論理演算子
演算子 意味
and 両方とも真。(「論理積」)
or 片方または両方が真。(「論理和」)
not 真ならば偽・偽ならば真。(「論理和」)
複数の比較演算子の連結

上記の例では、and 演算子の説明のため

  • x > 2 and x < 5

としていますが、これは

  • 2 < x < 5

と書くこともできます。両者は同じ意味になりますがxの参照は後者は一度だけになります。


match文[編集]

Python 3.10 から、パターンマッチングを行う match 文がサポートされました[5]

正規表現の match メソッドとは別です。

match文を使った条件分岐
for x in range(10):
    print(x,"=", end=" ")
    match x:
        case 2:
            print('two')
        case 5:
            print('five')
        case 7:
            print('seven')
        case _:
            print('ELSE')
実行結果
0 = ELSE
1 = ELSE
2 = two
3 = ELSE
4 = ELSE
5 = five
6 = ELSE
7 = seven
8 = ELSE
9 = ELSE
_ は、ワイルドカードバターンで全てにマッチします。

match文は、2021年に導入された新しい機能で、3.9以前のバージョンのpythonではmatch文は使えません。

パターン[編集]

Pythonの match 文で使用されるパターンは、以下のようなものがあります。

  • value パターン
  • ワイルドカード パターン
  • ガード パターン
  • type パターン
  • as パターン
  • or パターン
  • list パターン
  • tuple パターン
  • dict パターン
  • class パターン
  • シーケンス パターン

以下で、それぞれについて詳しく解説します。

value パターン[編集]

value パターンは、値が等しいかどうかを比較するためのパターンです。以下は、例です。

match color:
    case "red":
        print("赤色です")
    case "blue":
        print("青色です")
    case "green":
        print("緑色です")

この例では、color という変数に格納された値に応じて、条件分岐を行っています。case "red": は、color"red" と等しい場合にマッチします。

ワイルドカード パターン[編集]

ワイルドカードパターンは、どの値にもマッチするパターンです。ワイルドカードパターンは、_ という記号で表現します。

match value:
    case _:
        # valueがどの値にもマッチする場合の処理

ガード パターン[編集]

ガードパターンは、条件式が True である場合にマッチするパターンです。ガードパターンは、if キーワードを使って表現します。

match value:
    case x if x > 0:
        # valueが0より大きい場合の処理
    case y if y < 0:
        # valueが0より小さい場合の処理
    ...

type パターン[編集]

type パターンは、型が等しいかどうかを比較するためのパターンです。以下は、例です。

match value:
    case int:
        print("整数型です")
    case float:
        print("浮動小数点型です")
    case str:
        print("文字列型です")
    case _:
        print("不明な型です")

この例では、value という変数に格納された値の型に応じて、条件分岐を行っています。case int: は、value の型が整数型の場合にマッチします。

as パターン[編集]

as パターンは、値を別名で参照するためのパターンです。以下は、例です。

match value:
    case int as n:
        print("整数型です。値は", n, "です")
    case float as f:
        print("浮動小数点型です。値は", f, "です")
    case str as s:
        print("文字列型です。値は", s, "です")
    case _:
        print("不明な型です")

この例では、value という変数に格納された値の型に応じて、条件分岐を行っています。case int as n: は、value の型が整数型の場合にマッチし、value の値を n という名前で参照することができます。

or パターン[編集]

orパターンは、二つのパターンのいずれかにマッチする場合に使用されます。例えば、次のように使用します。

match x:
    case 0 or 1:
        print("x is either 0 or 1")
    case 2 or 3:
        print("x is either 2 or 3")
    case _:
        print("x is something else")

list パターン[編集]

listパターンは、リストに対してマッチする場合に使用されます。次のように、リストの要素を一つ一つマッチングします。

match my_list:
    case [0, 1]:
        print("my_list is [0, 1]")
    case [2, 3]:
        print("my_list is [2, 3]")
    case [4, _, _]:
        print("my_list starts with 4 and has at least 3 elements")
    case _:
        print("my_list is something else")

tuple パターン[編集]

tupleパターンは、タプルに対してマッチする場合に使用されます。リストの場合と同様に、タプルの要素を一つ一つマッチングします。

match my_tuple:
    case (0, 1):
        print("my_tuple is (0, 1)")
    case (2, 3):
        print("my_tuple is (2, 3)")
    case (4, _, _):
        print("my_tuple starts with 4 and has at least 3 elements")
    case _:
        print("my_tuple is something else")

dict パターン[編集]

dictパターンは、辞書に対してマッチする場合に使用されます。次のように、辞書のキーと値を一つ一つマッチングします。

match my_dict:
    case {'a': 1, 'b': 2}:
        print("my_dict is {'a': 1, 'b': 2}")
    case {'c': 3, 'd': 4}:
        print("my_dict is {'c': 3, 'd': 4}")
    case {'e': 5, 'f': _}:
        print("my_dict has the key 'e' with the value 5 and the key 'f' with some other value")
    case _:
        print("my_dict is something else")

class パターン[編集]

classパターンは、特定のクラスのインスタンスに対してマッチする場合に使用されます。次のように、クラス名を指定して、クラスのインスタンスにマッチングします。

class MyClass:
    def __init__(self, x, y):
        self.x = x
        self.y = y

match my_obj:
    case MyClass(0, 1):
        print("my_obj is an instance of MyClass with x=0 and y=1")
    case MyClass(2, 3):
        print("my_obj is an instance of MyClass with x=2

シーケンスパターン[編集]

Pythonのシーケンスパターンは、リスト、タプル、文字列、バイト列のようなシーケンス型のデータをマッチングするために使用されます。シーケンスパターンは、複数の要素を一度にマッチングするために使用され、組み込みの結合演算子を使用して複数のパターンを結合することができます。

以下は、シーケンスパターンを使用してリストをマッチングする例です。

match my_list:
    case [1, 2, 3]:
        print("Matched [1, 2, 3]")
    case [1, _, _]:
        print("Matched [1, _, _]")
    case [1, *rest]:
        print("Matched [1, *rest]")
        print("rest =", rest)
    case _:
        print("Matched anything else")

上記の例では、my_listが4つの異なるパターンにマッチするように定義されています。最初のパターン [1, 2, 3]は、my_listが要素が1, 2, 3のリストである場合にマッチします。2番目のパターン [1, _, _]は、my_listが最初の要素が1で、次の2つの要素が何であってもマッチします。3番目のパターン [1, *rest]は、my_listが最初の要素が1である場合にマッチし、*restはリストの残りの部分をキャプチャします。最後のパターン _は、どのリストにもマッチするため、最後のパターンは常に True を返します。

シーケンスパターンは、パターンの部分を任意の式で置き換えることができるため、マッチングされた要素にアクセスして処理を実行することができます。例えば、以下の例ではリストの最初の2つの要素にアクセスしていることがわかります。

match my_list:
    case [x, y, *rest]:
        print("First two elements:", x, y)
        print("Rest of the list:", rest)

この例では、xyは最初の2つの要素を表し、restは残りのリストを表します。 rest はキーワードではありませんが、レストパターンを引き受ける変数の名前としてよく使われます。

連想配列を使った多方向分岐[編集]

上の例は、連想配列を使って下のように書き換えることができます。

連想配列を使った例
h = { 2: "two", 5: "five", 7: "seven"}

for x in range(10) :
    print(f"{x} =", x in h and h[x] or "ELSE")

列挙型[編集]

Python 3.4からは、enumモジュールが標準ライブラリとして提供されています[6]

以下は、enumパッケージを使用した簡単な例です。

from enum import Enum

class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

このように、Enumを継承したクラスを作成し、クラス属性として定数を定義することで、独自の列挙型を定義できます。 上記の例では、Colorという列挙型を定義し、REDGREENBLUEという3つの定数を定義しています。

列挙型を使用すると、例えばColor.REDというように、定数に直接アクセスすることができます。

print(Color.RED)   # Color.RED
print(Color.RED.name)  # RED
print(Color.RED.value)  # 1

また、列挙型はforループを使って列挙することができます。

for color in Color:
    print(color)

match文と組み合わせると、列挙型の値に基づいた処理を簡潔に記述できます。

match color:
    case Color.RED:
        print("Red color")
    case Color.GREEN:
        print("Green color")
    case Color.BLUE:
        print("Blue color")

Python 3.10以降では、enumパッケージにauto()という新しい機能が導入されました。これにより、列挙型に自動的に連番の値を割り当てることができます。

from enum import Enum, auto

class Color(Enum):
    RED = auto()
    GREEN = auto()
    BLUE = auto()

for color in Color:
    print(color.value)

上記のコードでは、auto()を使用して列挙型に自動的に連番の値を割り当てています。結果として、Color.REDは1、Color.GREENは2、Color.BLUEは3の値を持ちます。

まとめ
# Enumクラスのインポート方法
from enum import Enum

# 基本的な列挙型の定義方法
class MyEnum(Enum):
    VALUE1 = 1
    VALUE2 = 2
    VALUE3 = 3

# 名前と値の一覧を取得する
print(list(MyEnum))

# 特定の名前に対応する値を取得する
print(MyEnum.VALUE1.value)

# 名前からEnumオブジェクトを取得する
print(MyEnum['VALUE2'])

# 値からEnumオブジェクトを取得する
print(MyEnum(3))

# Enumクラスを比較する
class MyEnum(Enum):
    VALUE1 = 1
    VALUE2 = 2
    VALUE3 = 3

class MyOtherEnum(Enum):
    VALUE1 = 1
    VALUE2 = 2
    VALUE3 = 3

print(MyEnum.VALUE1 == MyOtherEnum.VALUE1)  # False
print(MyEnum.VALUE1 == MyEnum.VALUE1)        # True

# Enumクラスを継承して新しい列挙型を定義する
class MyExtendedEnum(MyEnum):
    VALUE4 = 4
    VALUE5 = 5

# Enumクラスによる自動値付け
from enum import Enum, auto

class MyAutoEnum(Enum):
    VALUE1 = auto()
    VALUE2 = auto()
    VALUE3 = auto()

print(MyAutoEnum.VALUE1.value)  # 1
print(MyAutoEnum.VALUE2.value)  # 2
print(MyAutoEnum.VALUE3.value)  # 3

繰返し[編集]

繰返しに関するPythonの構文には、while文for文の2つがあります。

while文[編集]

while 文は、ある条件を満たすあいです、処理を繰返します。

構文
while 条件式 : 
    処理
コード例
i = "b"
while i != "q":
    i = input("入力した文字を3個、ならべるよ。(終了したい場合はqを入力)")
    print(3*i)
条件式は自動的に論理型に変換されます。
上記のプログラムを実行すると、まず「入力した文字を3個、ならべるよ。(終了したい場合はqを入力)」と言われます。
入力文字として、たとえば「a」と入力すると、「aaa」と出力表示され、そして再び「入力した文字を3個、ならべるよ。(終了したい場合はqを入力)」と聞かれ、ふたたび入力を待つ状態になります。なので、「b」と入力してみると、「bbb」と出力表示されます。
上記のプログラムは、文字「q」が入力されないかぎり、動作がつづく。文字「q」を入力することにより、終了します。

代入演算子[編集]

上記の while 文の例は、代入演算子をつかうと、

コード例(悪い例)
while (i := input("入力した文字を3個、ならべるよ。(終了したい場合はqを入力)")) != 'q' :
    print(3*i)
のように書換えることができます。

while文とif文との組合わせ[編集]

while文はif文と組合わせることもできます。

while文とif文との組合わせ(悪い例)
while (i := input("文字を入力しましょう。sを入力で物語がスタート。(終了したい場合はqを入力)")) != 'q' :
    if i == "s":
        print("はじまりはじまり。")
        print("むかし、むかし、あるところに、")
        print("おじいさんとおばあさんが、すんでいました。")
        print("おしまい")
上記のプログラムを実行すると、文字「s」を入力することで「はじまりはじまり。」と表示させることができ、そして「むかし、むかし、あるところに、」「おじいさんとおばあさんが、すんでいました。」「おしまい」と表示します。
sを入力しなければ、「はじまりはじまり。」などは表示されません。
このコードは、while の条件式に入力のロジックと終了条件のロジックを合成して読解と修正を困難にしている悪い例です。#break文に改善した例があります。

for文[編集]

素朴なfor文
for i in range(5):
    print("a")
のように書いて実行すると、組込み関数range()のカッコ内の回数だけ、ブロック内の文を繰り返す。上のコードの場合、実行すると、「a」を5回、表示します。
実行結果
a
a
a
a
a

forのあとの変数(ループ変数と呼ばれます)は、別にiである必要はなく、特に以後値を参照しない場合は _ を使うと慣習的に「参照しないこと」が明示できます。

ループ変数が以後参照しないことを明示している例
for _ in range(5):
    print("a")

ただし、あくまで慣習にすぎず、言語仕様上は _ という名前の変数にすぎないので、_ の値を参照するプログラムを書けば実行でき、インタプリターは何の警告もしません。 また、pylint の様な静的なソースコード診断ツールでは、_ は未使用変数のチェックの対象から外されているなど、言語仕様ではないものの _ を特別な識別子として扱う事は慣例的に定着しているので、_ の値を参照するコードを書かないことを強く推奨します。

慣習上、for文を書くときは、i で回数を数えることが多い[7]

for i in range(5):
    print(i)

のように、すると、

実行結果
0
1
2
3
4

のように表示されます。 組込み関数 range() は range クラスのオブジェクトを返します。

range以外のオブジェクトとfor文の組み合わせ[編集]

range以外のオブジェクトとfor文の組み合わせ
li = [2, 3, 5]
tu = (10, 20, 30)

for i in li:
    print(i, end=", ")
else:
    print()

for i in tu:
    print(i, end=", ")
else:
    print()

for i, j in zip(li, tu):
    print(i, j, sep=":", end=", ")
else:
    print()

print(type(zip(li, tu)))
実行結果
2, 3, 5, 
10, 20, 30, 
2:10, 3:20, 5:30, 
<class 'zip'>

continue文[編集]

continue文は、ループの先頭に戻ります。continue文を含むループのブロックのcontinue文以降は実行されません。

pass文[編集]

pass文は、なにもしません。 「なにもしないが構文上ブロックが要求される」ケースで使われます。

break文[編集]

while文あるいはfor文のブロックで文「break」を使うと、ループを中断します。

i = "b"
while True:
    i = input("文字を入力しましょう。sを入力で物語がスタート。(終了したい場合はqを入力))
    if i == "s":
        print("はじまりはじまり。")
        print("むかし、むかし、あるところに、")
        print("おじいさんとおばあさんが、すんでいました。")
        print("おしまい")
    elif i == "q":
        break

break文で中断する対象は、if文ではありません。break文は、ループを中断するものです。

なおwhile Trueのように、while直後の条件式をブール値 True にすると、条件式は常に真となり、永久ループとなります[8]

ループにつづくelse節[編集]

while文あるいはfor文がbreak文で中断しなかった場合forにつづくelse節が実行されます。else節は、大概のプログラミング言語ではif文と組合わせて使いますが、Pythonではこれに加え繰返し(while文あるいはfor文)と組合わせることができます。

while+else[編集]

while+else
i = 0
while i < 100:
    print(i, end=" ")
    i += 3
else:
    print("done!")

i = 0
while i < 100:
    if i > 10:
        break
    print(i, end=" ")
    i += 3
else:
    print("done!")
実行結果
0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 done!
0 3 6 9
ループを完走した場合は else 節を実行し、break (や return)で中断すると else 節は実行されません。
1つ目のwhileループは、変数iを0から3ずつ増やし、100以上になるまでループを繰り返します。ループの本体では、変数iの値を印刷します。end=" "は、印刷された各値の後に空白を追加し、すべてを1行に表示するためのものです。最後に、else節で"done!"というメッセージを印刷します。
2つ目のwhileループは、変数iを0から3ずつ増やし、10を超えるまでループを繰り返します。ループの本体では、変数iの値を印刷し、それが10を超えた場合は、breakステートメントが呼び出され、ループが終了します。最後に、else節が実行されず、"done!"というメッセージは印刷されません。
ループと結合したelseの使いどころ
Pythonでは、ループが完走したときに実行されるelse節を置くことができます。

では、このelse節は何に使うのでしょう?

1000以下の素数を求める(フラッグ版)
i = 2
while i <= 1000:
    j = 2
    is_prime = True
    while j * j <= i:
        if i % j == 0:
            is_prime = False
            break
        j += 1
    if is_prime:
        print(i, end=" ")
    i += 1
break で抜けたかをフラッグ is_prime で判断しています。
ゴチャゴチャしています。
1000以下の素数を求める(else版)
i = 2
while i <= 1000:
    j = 2
    while j * j <= i:
        if i % j == 0:
            break
        j += 1
    else:
        print(i, end=" ")
    i += 1
フラッグがなくなり簡素になりました。
1000以下の素数を求める(for+range版)
for i in range(2, 1000):
    for j in range(2, i):
        if i % j == 0:
            break
    else:
        print(i, end=" ")
こちらの方がより簡潔ですね。
while版と比べ内側のループが廻りすぎていますが(本来 sqrt(i)までで良い)、j2がなくなっているので1000までの区間なら性能劣化は軽微。
1000以下の素数を求める(素数集合更新版)
primes = []
for i in range(2, 1000):
    for prime in primes:
        if i % prime == 0:
            break
    else:
        primes.append(i)
        print(i, end=" ")
素数の集合を保持するリスト primes を導入しました
i の因数が primes になければ、iprimes に追加するロジックです
primes は素数が小さい順に保持されるので最も効率よく因数を探せます。

ループ完走のelseを使うと、「因数が見つからなかった」ケースをフラッグなしに表現でき、記述力が向上し、より洗練されたアルゴリズムの探求に貢献しています。 もし、素数集合更新版をフラッグで表現したら、これより遥かに記述性が劣るでしょう。

Python以外の言語では、Zigでも else を伴ったループ構文があります。


for+else[編集]

for+else
h = {2: "two", 5: "five", 7: "seven"}

for x in list(h):
    print(h[x])
else:
    print("I didn't take a break.")

for x, v in h.items():
    if x == 7:
        break
    print(x, v)
else:
    print("I didn't take a break.")
実行結果
two
five
seven
I didn't take a break.
2 two
5 five
ループをカンストした場合は else 節を実行し、break (や return)で中断すると else 節は実行されません。
ループとelseを組合わせた大域脱出
Pythonはgoto分やラベル付きbreak文を持っていないので、大域脱出する場合は
  • ループ全体を関数にしてreturn文で脱出
  • tryをループをくくり例外をあげて脱出
  • プログラム自身を終了

などの工夫が必要です。

ここでは、ループと結合したelseを使った大域脱出を紹介します。

ループと結合したelseを使った大域脱出
for i in range(10):
    for j in range(10):
        for k in range(10):
            if (i == 2 and j == 3 and k == 5):
                break
            print(f"{i}{j}{k}", end=" ")
        else:
            print()
            continue
        break
    else:
        continue
    break
else:
    print("done!")
実行結果
000 001 002 003 004 005 006 007 008 009 
010 011 012 013 014 015 016 017 018 019 
020 021 022 023 024 025 026 027 028 029 
030 031 032 033 034 035 036 037 038 039 
040 041 042 043 044 045 046 047 048 049 
050 051 052 053 054 055 056 057 058 059 
060 061 062 063 064 065 066 067 068 069 
070 071 072 073 074 075 076 077 078 079 
080 081 082 083 084 085 086 087 088 089 
090 091 092 093 094 095 096 097 098 099 
100 101 102 103 104 105 106 107 108 109 
110 111 112 113 114 115 116 117 118 119 
120 121 122 123 124 125 126 127 128 129 
130 131 132 133 134 135 136 137 138 139 
140 141 142 143 144 145 146 147 148 149 
150 151 152 153 154 155 156 157 158 159 
160 161 162 163 164 165 166 167 168 169 
170 171 172 173 174 175 176 177 178 179 
180 181 182 183 184 185 186 187 188 189 
190 191 192 193 194 195 196 197 198 199 
200 201 202 203 204 205 206 207 208 209 
210 211 212 213 214 215 216 217 218 219 
220 221 222 223 224 225 226 227 228 229 
230 231 232 233 234
最外周のprint("done!")は(breakされた場合は)実行されません。


ループはスコープを作りません[編集]

Pythonでは、ループはスコープを作りません。

ループはスコープを作りません
i = "abc"
j = "xyz"
print(f"forの前: {i=}{j=}")
for i in range(5):
    j = 2 * i
    print(f"forの中: {i=}{j=}")
print(f"forの後: {i=}{j=}")
実行結果
forの前: i='abc'、j='xyz'
forの中: i=0、j=0
forの中: i=1、j=2
forの中: i=2、j=4
forの中: i=3、j=6
forの中: i=4、j=8 
forの後: i=4、j=8

脚註[編集]

  1. ^ 関数やメソッドの呼出しや復帰 return も制御構造と言えますが、本項では逐次・分岐・繰返しについて述べます。
  2. ^ 4.1. if Statements” (2021年11月17日). 2021年11月18日閲覧。
  3. ^ else節は、他の言語と違いfor文とも結合しますので注意してください。
  4. ^ ただし、Pythonでは math.asin(2) ↑ValueError であったりnanを返す前に例外が上がる事が多々あります。
  5. ^ 4.6. match Statements” (2021年11月17日). 2021年11月18日閲覧。
  6. ^ enum — Support for enumerations” (2021年11月17日). 2021年11月18日閲覧。
  7. ^ 少なくともFortranではdo文のループ変数に i が常用され、それ以前に数学でも数列の和など i が使用されます。由来は、iteration の i; integer の i など諸説あります。
  8. ^ while 1:としても無限ループになりますが、これは整数型が論理型に変換されるとき「0はFalse, 0以外はTrue」に暗黙に変換されることに頼っています(意味を明示するためwhile True:とすべき)。同様にwhile i:として、ループ変数 i がゼロになるまで繰り返すのようなコードも暗黙変換に頼っています。このようなコードは小さな変更で最初の意図に反した挙動を示します。たとえば i-=1 を i-=2 にした場合、i=1の次はi=-1となり、ループ終了条件のi=0を経ることなく無限ループになります。この場合は while i > 0:とすべきです。