Python/条件分岐と繰り返し
Python の制御構造には、逐次・分岐・繰返しの3つがあり。このうち逐次はプログラムが左上から左から右・上から下に進む当たり前の状態ですので、これ以上の説明は必要ないと思います[1]。
条件分岐[編集]
Pythonでは条件分岐をするために if
文あるいは match
文を使います。
if文[編集]
Pythonでは条件分岐をするために if
文を使います[2]。基本的な形は以下のようになります:
if 条件: 条件が真の場合に実行されるコード elif 別の条件: 別の条件が真の場合に実行されるコード else: どの条件も満たされない場合に実行されるコード
例えば、ある変数 x
の値に基づいて条件分岐する場合を考えてみましょう:
x = 10 if x > 10: print("xは10より大きいです") elif x < 10: print("xは10より小さいです") else: print("xは10です")
この場合、x
の値が10なので、最初の条件と最後の条件のどちらも満たされますが、最初の条件が先に評価されます。そのため、"xは10です" と出力されます。
条件分岐を使うことで、プログラムが特定の条件下で異なる動作をするように制御することができます。
match 文[編集]
Python 3.10以降では、match文が導入されました[3]。match文は、特定の値に基づいてパターンをマッチングし、対応するブロックを実行するのに使用されます。match文は、複数の値や条件を一度に比較し、コードをより読みやすくし、処理をシンプルにするのに役立ちます。
以下は、match文の基本的な使い方です:
def check_value(x): match x: case 1: print("xは1です") case 2: print("xは2です") case _: print("その他の値です")
この例では、x の値に応じて異なる処理を行います。match文では、caseキーワードを使用して値やパターンを指定し、そのパターンがマッチした場合に対応するブロックが実行されます。また、case _:のように_を使用することで、どのケースにもマッチしない残りのケースを処理することができます。
さらに、match文では複数の条件やパターンをまとめて処理することもできます。例えば、タプルやリスト、または|演算子を使用して複数の条件を指定できます:
def check_pair(pair): match pair: case (0, 0): print("原点です") case (x, y) if x == y: print("xとyは同じ値です") case (x, _) if x > 0: print("xは正の値です") case _: print("その他のケースです")
この例では、(0, 0)ならば原点、(x, y)でxとyが同じなら同じ値、(x, _)でxが正の値なら正の値、それ以外のケースを処理します。
match文はパターンマッチングを使用して柔軟な条件分岐を行うのに役立ちます。これにより、コードの読みやすさと保守性を向上させることができます。
条件式[編集]
条件式はプログラミングで特定の条件が成立するかどうかを判定するために使われます。Pythonでは、if
文を使って条件式を評価し、条件が真である場合に特定のコードブロックを実行します。
基本的な構文は以下のようになります:
if 条件式: 条件が真の場合に実行されるコード else: 条件が偽の場合に実行されるコード
else
は省略可能で、条件が偽の場合に何も実行しないようにすることができます。
比較演算子や論理演算子[編集]
Pythonでは比較演算子や論理演算子を使って条件式を組み立てることができます。主な比較演算子は以下の通りです:
==
: 等しい!=
: 等しくない<
: より小さい>
: より大きい<=
: 以下>=
: 以上
例えば:
x = 5 if x == 5: print("xは5です") else: print("xは5ではありません")
- 比較演算の特異な例
x = float("nan") if x > 0.0: print("xは正の数です") elif x < 0.0: print("xは負の数です") elif x == 0.0: print("xは零です") else: print(f"xは{x}です")
- 実行結果
xはnanです
nanってナニ? |
唐突に float("nan") 、が出てきましたが、これがPythonでNaN(Not a Number; 非数)を得る方法で、他には math を import して math.nan を使う方法もあります。
nan は、浮動小数点演算の結果として、不正なオペランドを与えられたために生じた結果を表す値またはシンボルで[4]、NaNの体系的仕様は、無限大の表現などと共に1985年の IEEE 754 浮動小数点規格で標準が与えられています。
|
さらに、複数の条件を組み合わせるために論理演算子を使用できます:
and
: 論理積(両方の条件が真である場合に真)or
: 論理和(どちらかの条件が真である場合に真)not
: 否定(条件の反対)
例えば:
x = 10 y = 5 if x > 5 and y < 10: print("xは5より大きく、yは10より小さいです")
このようにして、条件式を使うことでプログラム内で特定の条件が成立するかどうかを判断し、それに応じた処理を行うことができます。
複数の比較演算子の連結 |
上記の例では、and 演算子の説明のため
としていますが、これは
と書くこともできます。両者は同じ意味になりますがxの参照は後者は一度だけになります。 |
in 演算子[編集]
in
演算子はPythonで非常に便利な演算子の1つです。in
演算子は特定の要素がコレクション(リスト、タプル、文字列など)に含まれているかどうかをチェックするのに使います。
例えば、リスト内に特定の要素が含まれているかを確認する場合に使えます:
my_list = [1, 2, 3, 4, 5] if 3 in my_list: print("3はリスト内に含まれています")
同様に、文字列内で特定の部分文字列が存在するかを確認することもできます:
my_string = "Hello, World!" if "Hello" in my_string: print("文字列内に'Hello'が含まれています")
in
演算子は、リストや文字列の他にも、辞書や集合などのコレクションでの要素の存在をチェックするのに役立ちます。条件式にin
演算子を使うことで、特定の要素がコレクションに含まれているかどうかを簡単に判断できます。
様々な型の論理値への変換[編集]
Pythonの条件式では、整数、文字列、リストなどのさまざまなデータ型を使用することができます。条件式では、その値が真か偽かを判定します。
整数を条件式として使用する場合、0は偽として扱われ、0以外の整数は真として扱われます。例えば:
x = 5 if x: print("xは真です") else: print("xは偽です")
ここでは、x
が0以外の値(真)を持っているため、"xは真です"と出力されます。
文字列やリストなどのシーケンスも条件式として使用できます。空の文字列や空のリストは偽として扱われます。例えば:
my_string = "" my_list = [] if my_string or my_list: print("空ではありません") else: print("空です")
上記の場合、my_string
とmy_list
の両方が空なので、"空です"と出力されます。
このように、Pythonの条件式では値が真か偽かを判定し、それに基づいてコードを実行することができます。整数、文字列、リストなど、さまざまなデータ型を条件式として使用することで、柔軟な条件分岐を行うことができます。
if 式[編集]
Pythonのif
文は、条件に基づいてコードの実行を制御するためのものでしたが、Python3.8からはif
式(または三項演算子)が導入されました。if
式は、1行で条件に応じて値を返すことができます。
if
式の基本的な構文は以下の通りです:
value_if_true if condition else value_if_false
これは、条件が真の場合にvalue_if_true
を返し、偽の場合にvalue_if_false
を返します。
例えば、次のように使えます:
x = 5 result = "Even" if x % 2 == 0 else "Odd" print(result)
この場合、x
が偶数なら"Even"
が、奇数なら"Odd"
が出力されます。
このように、if
式を使うと簡潔に条件に応じて値を設定したり、返したりすることができます。特に、1行で簡潔に条件式を表現したい場合に便利です。
内包表記とif式[編集]
内包表記とif
式は、Pythonでコードを短く、効率的に書くための強力な機能です。
内包表記は、リスト、集合、辞書などのデータ構造を構築するための簡潔な方法です。if
式を内包表記に組み込むことで、特定の条件を満たす要素のみを含むリストや集合を生成できます。
リスト内包表記でif
を使う例を見てみましょう:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 偶数のみを含むリストを生成する even_numbers = [x for x in numbers if x % 2 == 0] print(even_numbers)
このコードでは、numbers
リストから偶数のみを取り出してeven_numbers
リストを生成しています。リスト内包表記の中でif
を使用することで、条件に合致する要素だけを含むリストを作成できます。
同様に、辞書内包表記や集合内包表記でもif
式を使用できます。例えば:
# 辞書内包表記で奇数とその2乗を辞書にする odd_squares_dict = {x: x**2 for x in numbers if x % 2 != 0} print(odd_squares_dict) # 集合内包表記で偶数の集合を生成する even_set = {x for x in numbers if x % 2 == 0} print(even_set)
これらの例は、内包表記を使って条件に基づいてリスト、辞書、集合を生成する方法を示しています。if
式を内包表記に組み込むことで、コンパクトで読みやすいコードを書くことができます。
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)
この例では、x
とy
は最初の2つの要素を表し、rest
は残りのリストを表します。
rest
はキーワードではありませんが、レストパターンを引き受ける変数の名前としてよく使われます。
連想配列を使った多方向分岐[編集]
match文の最初の例は、辞書を使って下のように書き換えることができます。
- 辞書を使った例
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
という列挙型を定義し、RED
、GREEN
、BLUE
という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には、さまざまな繰り返しの方法があります。主なものは for
ループと while
ループです。
for
ループ:[編集]
for
ループは、リスト、タプル、辞書、集合などのイテラブル(要素を一つずつ取り出せるオブジェクト)を繰り返し処理するのに使います。
リストの例:
fruits = ["apple", "banana", "cherry"] for fruit in fruits: print(fruit)
fruits
リスト内の各要素を順番に取り出して、その要素をfruit
という変数に格納してループ内で使用しています。
辞書の例:
person = {"name": "Alice", "age": 30, "city": "New York"} for key, value in person.items(): print(f"{key}: {value}")
items()
メソッドを使って辞書のキーと値のペアを取得し、key
とvalue
にそれぞれ格納しています。
while
ループ:[編集]
while
ループは指定された条件が真の間、繰り返し処理を実行します。
count = 0 while count < 5: print(count) count += 1
この例では、count
が5未満の場合にループが実行され、count
の値が表示されます。count += 1
によってcount
が1ずつ増加します。
:= 演算子[編集]
:=
演算子はPython 3.8で導入された「セイウチ演算子(Walrus operator)」として知られています。これは式内で変数に値を代入するためのもので、通常の代入文とif
文を組み合わせたような構文を、より簡潔に記述できるようにします。
例えば、while
ループでの使用方法を見てみましょう:
total = 0 while (input_value := int(input("Enter a number (0 to stop): "))) != 0: total += input_value print(f"The total is: {total}")
この例では、input()
関数を使ってユーザーから数値を入力し、:=
演算子を使用して同時にinput_value
に代入しています。そして、入力された値が0でない限り、ループは継続され、total
に入力値を加算し続けます。入力された数値が0であればループは終了し、最終的な合計値が表示されます。
この演算子は、ループ内で変数を初めて定義する際や、式内で一時的な変数を使う場合などに特に便利です。ただし、適切に使うことでコードの読みやすさを損なわないように注意が必要です。
制御構造:[編集]
break
やcontinue
などの制御構造も使えます。break
はループを抜け出し、continue
はループの現在のイテレーションをスキップして次のイテレーションに進みます。
for i in range(10): if i == 3: continue if i == 8: break print(i)
この例では、continue
はi
が3のときに処理をスキップし、break
はi
が8のときにループを抜けます。
これらの方法を使って、Pythonで繰り返し処理を行う機能を活用することができます。
ループにつづく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節は何に使うのでしょう?
ループ完走の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文を持っていないので、大域脱出する場合は
などの工夫が必要です。 ここでは、ループと結合したelseを使った大域脱出を紹介します。
|
ループはスコープを作りません[編集]
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
脚註[編集]
- ^ 関数やメソッドの呼出しや復帰 return も制御構造と言えますが、本項では逐次・分岐・繰返しについて述べます。
- ^ “4.1. if Statements” (2024年1月6日). 2024年1月17日閲覧。
- ^ “4.1. if Statements” (2024年1月6日). 2024年1月17日閲覧。
- ^ ただし、Pythonでは math.asin(2) ↑ValueError であったりnanを返す前に例外が上がる事が多々あります。
- ^ “4.6. match Statements” (2021年11月17日). 2021年11月18日閲覧。
- ^ “enum — Support for enumerations” (2021年11月17日). 2021年11月18日閲覧。