Python言語の文法を、コードを書く流れに沿って説明していく連載。今回は制御構文のうち、条件分岐について説明する。ロジックや処理フローを定義するための大事な文法である。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
ご注意:本記事は、@IT/Deep Insider編集部(デジタルアドバンテージ社)が「deepinsider.jp」というサイトから、内容を改変することなく、そのまま「@IT」へと転載したものです。このため用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。
前回は「関数の定義方法」について紹介した。今回は、プログラムの処理フローを作るのに欠かせない「制御構文(条件分岐)」について説明する。※脚注や図、コードリストの番号は前回からの続き番号としている。
本連載は、実際にライブラリ「TensorFlow」でディープラーニングのコードを書く流れに沿って、具体的にはLesson 1で掲載した図1-a/b/c/dのサンプルコードの順で、基礎文法が学んでいけるように目次を構成している。今回は、図1-b/d内の一部コードを取り上げる。
今回、本稿で説明するのは図1-b/d【再掲】における赤枠内のコードのみとなる。
なお、本稿で示すサンプルコードの実行環境については、Lesson 1を一読してほしい。
Lesson 1でも示したように、本連載のすべてのサンプルコードは、下記のリンク先で実行もしくは参照できる。
プログラミングは、ロジック(=思考の道筋、論理)や処理フロー(=流れ)の連続で形作られる。そこで必要となるのが、「もし□□であれば、○○をする。そうでなければ××をする」といった条件分岐や、「データの最後まで、順番に1件ずつ○○をする」といったループ処理(=繰り返し処理)、といったロジック/フローを制御するための構文である。
そこで、今回は条件分岐を、次回Lesson 10ではループ処理を説明する。
「もし□□であれば」から想像が付くように、条件分岐を実現するのは、ifキーワードを使った構文である。図1-bの中ほどに、実際にそのif文がある。それを抜き出したのがリスト12-1である。
predicted_label = '猫'
true_label = '犬'
# 上の2行は下記コードの実行に必要な仮のコード
if predicted_label == true_label:
color = 'blue'
else:
color = 'red'
color # 'red'と出力される
このif文コードの構造をイメージにしたのが図13-1である。
基本的な書き方は、前回Lesson 08で説明した関数定義と似ているのが分かるだろう。インデントについて、関数では「スコープ」とも書いたが、ここでは「ブロック」と表現している。条件分岐の説明を優先して、両者の違いについては次節で述べることにする。
関数定義であればdefだったところが、条件分岐では「もし□□であれば」を意味するifに代わり、「ブロックの開始」を意味するコロン:がやはり使われている。ブロックにはインデントを付けて、条件が真(True)であるときに実行する処理内容が記載されている。
続けて、インデントを解除してブロックが終了された後、「そうでなければ」を意味するelseキーワードとコロン:が使われている。再度、インデントを付けて、条件が偽(False)であるときに実行する処理が記載されている。
先ほども説明したが、Pythonにおいてはインデントがブロック(つまり範囲)を決めるので、インデントをきれいに整えるのに細心の注意を払う必要がある*6。
*6 ちなみに、多くの他の言語(JavaScriptやC言語など)では、見やすさのためにインデントは付けるものの、それによってブロックが決まる仕様ではないので、インデントがずれても問題にはならない。しかしPythonでは問題が生じる。つまり、インデントの取り扱いに柔軟性がない。ただし「柔軟性がない」ことがデメリットというわけではなく、「誰が書いても見やすいコードになるメリットがある」と考える人もいる。この点が「Pythonが好きか嫌いか」を分ける大きな要因の一つにもなっている。最近では、「Pythonは数学関連ライブラリが充実しているメリットが大きい」ということで、好き嫌いは別にして、Pythonの利用者数は着実に増えている。
条件の部分はpredicted_label == true_labelというコードになっている。これは、「predicted_label(予測ラベル)がtrue_label(教師ラベル)と==(イコール)であるか?」という式(expression)になっている。この式は、TrueかFalseのbool値(真偽値)を返す。それがTrueであればif文の配下ブロックにあるcolor = 'blue'(=変数colorに'blue'という値を代入)が実行され、Falseであればelse文の配下ブロックにあるcolor = 'red'が実行される。
==(※半角のイコールが2つ)のように、左辺 == 右辺という式で、左辺と右辺を比較する記号を、比較演算子と呼ぶ。比較演算子は表2のものが用意されている。
比較演算子 | 記述例 | 意味 |
---|---|---|
== | a == b | bが、aに等しい |
!= | a != b | bが、aに等しくない |
> | a > b | bより、aが大きい |
>= | a >= b | bより、aが大きいか等しい |
< | a < b | bより、aが小さい |
<= | a <= b | bより、aが小さいか等しい |
表2 条件で使える比較演算子 |
先ほどの例はシンプルな2分岐の条件判定だった。しかし、「もし□□であれば(if)」「もしくは◇◇であれば」「もしくは☆☆であれば」「それら以外であれば(else)」というように、3つ以上の分岐をしたい場合もあるかもしれない。このような場合には、elif文を間に追加すればよい。例えばリスト12-2のようになる(※イメージは先ほどとほぼ同じなので割愛)。
predicted_label = '猫' # この行は下記コードの実行に必要な仮のコード
if predicted_label == '犬':
color = 'blue'
elif predicted_label == '猫':
color = 'green'
elif predicted_label == '馬':
color = 'yellow'
else:
color = 'red'
color # 'green'と出力される
また、elseを加えずに条件分岐を作ることもできる。リスト12-3がその例だ。ここではelif文を加えているが、これを無くして、if文単独の条件分岐にすることも可能だ。
predicted_label = '猫' # この行は下記コードの実行に必要な仮のコード
color = 'white'
if predicted_label == '犬':
color = 'blue'
elif predicted_label == '羊':
color = 'pink'
color # 'white'と出力される
ちなみにPython以外のプログラミング言語をかじったことがあれば、switch文による条件分岐はないのか、という疑問があるかもしれない。Pythonにはswitch文に相当する構文はないので、elif文を駆使して、3つ以上の条件分岐を行う必要がある。
さて、ここまで説明を保留してきたブロックとスコープだが、必要な構文の説明が終わったので、ここらで詳しく説明しておこう。
関数の場合は、「ブロック」であり「スコープ」でもあると説明した。このスコープとは、関数(=def文のは配下の)とモジュールにおいて適用される概念である。ブロック(block)が「開始〜終了の範囲」を表すのに対し、スコープ(scope)は「変数などにアクセスできる範囲」を表す。
if文はブロックを明示するが、スコープではない。例えばリスト12-4で、if文による条件分岐の配下にあるブロックでcolor = 'blue'と変数の宣言と代入が行われているが、最下行にcolorと記載されており、if文のブロックの外から、変数colorにアクセスしている。これは、変数colorがモジュール内の「全体」を意味するグローバルスコープで生成されているためだ。グローバルスコープの変数は、グローバル変数とも呼ばれる。なお、ここで言うモジュールとはPythonファイル(.pyファイル)のことであり、Google ColabやJupyter Notebookにおいてはノートブック(.ipynbファイル)のことである。
predicted_label = 100 # この行は下記コードの実行に必要な仮のコード
if predicted_label == 100:
animal = 'イヌ' # グローバルスコープでの変数宣言になる
animal # 'イヌ'と出力される
一方、リスト12-5のようにdef文による関数の配下にあるブロックでsize = 10と変数の宣言と代入を行った場合、この変数sizeには関数の外部からはアクセスできない。これは、変数sizeが関数のブロック内のみのローカルスコープで生成されているためだ。ローカルスコープの変数は、ローカル変数とも呼ばれる。
def some_function():
size = 10 # ローカルスコープでの変数宣言になる
some_function() # 関数を呼び出す
size # 変数は定義されてないとしてNameError(名前のエラー)になる
図13-2では、グローバルスコープとローカルスコープの違いを比較している。
要するに、関数内(もしくはクラスのメソッド内)で宣言した変数は、関数(やメソッド)の外では使えない。関数以外で宣言した変数は、同一ファイル内であれば使える、と覚えておけばよい。
Copyright© Digital Advantage Corp. All Rights Reserved.