機械学習 & ディープラーニング入門(Python編)[Lesson 9]

機械学習 & ディープラーニング入門(Python編)[Lesson 9]

条件分岐 ― Python基礎文法入門

2019年4月8日

Python言語の文法を、コードを書く流れに沿って説明していく連載。今回は制御構文のうち、条件分岐について説明する。ロジックや処理フローを定義するための大事な文法である。

一色政彦 デジタルアドバンテージ 一色 政彦

 前回は「関数の定義方法」について紹介した。今回は、プログラムの処理フローを作るのに欠かせない「制御構文(条件分岐)」について説明する。脚注や図、コードリストの番号は前回からの続き番号としている。

 本連載は、実際にライブラリ「TensorFlow」でディープラーニングのコードを書く流れに沿って、具体的にはLesson 1で掲載した図1-a/b/c/dのサンプルコードの順で、基礎文法が学んでいけるように目次を構成している。今回は、図1-b/d内の一部コードを取り上げる。

TensorFlowの公式チュートリアルのサンプルコード
図1-b【再掲】 TensorFlowの公式チュートリアルのサンプルコード(2)
TensorFlowの公式チュートリアルのサンプルコード
図1-d【再掲】 TensorFlowの公式チュートリアルのサンプルコード(4)

 今回、本稿で説明するのは図1-b/d【再掲】における赤枠内のコードのみとなる。

 なお、本稿で示すサンプルコードの実行環境については、Lesson 1を一読してほしい。

 Lesson 1でも示したように、本連載のすべてのサンプルコードは、下記のリンク先で実行もしくは参照できる。

Google Colabで実行する
GitHubでソースコードを見る

Python言語の基礎文法

 プログラミングは、ロジック(=思考の道筋、論理)や処理フロー(=流れ)の連続で形作られる。そこで必要となるのが、「もし□□であれば、○○をする。そうでなければ××をする」といった条件分岐や、「データの最後まで、順番に1件ずつ○○をする」といったループ処理(=繰り返し処理)、といったロジック/フローを制御するための構文である。

 そこで、今回は条件分岐を、次回Lesson 10ではループ処理を説明する。

条件分岐

 「もし□□であれば」から想像が付くように、条件分岐を実現するのは、ifキーワードを使った構文である。図1-bの中ほどに、実際にそのif文がある。それを抜き出したのがリスト12-1である。

Python
predicted_label = '猫'
true_label = '犬'
# 上の2行は下記コードの実行に必要な仮のコード

if predicted_label == true_label:
  color = 'blue'
else:
  color = 'red'

color  # 'red'と出力される
リスト12-1 条件分岐を行うコード例

 このif文コードの構造をイメージにしたのが図13-1である。

条件分岐、のイメージ
図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)になっている。この式は、TrueFalseのbool値(真偽値)を返す。それがTrueであればif文の配下ブロックにあるcolor = 'blue'(=変数color'blue'という値を代入)が実行され、Falseであればelse文の配下ブロックにあるcolor = 'red'が実行される。

 ==半角のイコールが2つ)のように、左辺 == 右辺という式で、左辺と右辺を比較する記号を、比較演算子と呼ぶ。比較演算子は表2のものが用意されている。

比較演算子記述例意味
==a == bbが、aに等しい
!=a != bbが、aに等しくない
>a > bbより、aが大きい
>=a >= bbより、aが大きいか等しい
<a < bbより、aが小さい
<=a <= bbより、aが小さいか等しい
表2 条件で使える比較演算子

 先ほどの例はシンプルな2分岐の条件判定だった。しかし、「もし□□であれば(if)」「もしくは◇◇であれば」「もしくは☆☆であれば」「それら以外であれば(else)」というように、3つ以上の分岐をしたい場合もあるかもしれない。このような場合には、elif文を間に追加すればよい。例えばリスト12-2のようになる(イメージは先ほどとほぼ同じなので割愛)。

Python
predicted_label = '猫'  # この行は下記コードの実行に必要な仮のコード

if predicted_label == '犬':
  color = 'blue'
elif predicted_label == '猫':
  color = 'green'
elif predicted_label == '馬':
  color = 'yellow'
else:
  color = 'red'

color  # 'green'と出力される
リスト12-2 3つ以上の条件分岐を行うコード例

 また、elseを加えずに条件分岐を作ることもできる。リスト12-3がその例だ。ここではelif文を加えているが、これを無くして、if文単独の条件分岐にすることも可能だ。

Python
predicted_label = '猫'  # この行は下記コードの実行に必要な仮のコード

color = 'white'

if predicted_label == '犬':
  color = 'blue'
elif predicted_label == '羊':
  color = 'pink'

color  # 'white'と出力される
リスト12-3 else文が含まれない条件分岐のコード例

 ちなみに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ファイル)のことである。

Python
predicted_label = 100  # この行は下記コードの実行に必要な仮のコード

if predicted_label == 100:
  animal = 'イヌ'  # グローバルスコープでの変数宣言になる

animal  # 'イヌ'と出力される
リスト12-4 if文内の変数宣言はグローバルスコープで宣言されている

 一方、リスト12-5のようにdef文による関数の配下にあるブロックでsize = 10と変数の宣言と代入を行った場合、この変数sizeには関数の外部からはアクセスできない。これは、変数sizeが関数のブロック内のみのローカルスコープで生成されているためだ。ローカルスコープの変数は、ローカル変数とも呼ばれる。

Python
def some_function():
  size = 10  # ローカルスコープでの変数宣言になる

some_function()  # 関数を呼び出す
size  # 変数は定義されてないとしてNameError(名前のエラー)になる
リスト12-5 関数定義内の変数宣言はローカルスコープで宣言されている

 図13-2では、グローバルスコープとローカルスコープの違いを比較している。

グローバルスコープとローカルスコープ
図13-2 グローバルスコープとローカルスコープ

 要するに、関数内(もしくはクラスのメソッド内)で宣言した変数は、関数(やメソッド)の外では使えない。関数以外で宣言した変数は、同一ファイル内であれば使える、と覚えておけばよい。

 ちなみに応用的な文法になるが、リスト12-6のように、関数内でglobal sizeglobalキーワードの後に半角スペースを入れて変数名)と記載すれば、その関数が呼び出された際に、変数sizeはグローバル変数扱いになる。

Python
def some_function():
  global size  # グローバルスコープでの変数宣言になる
  size = 10

some_function()  # 関数を呼び出す
size  # 10と出力される
リスト12-6 関数定義内でグローバル変数を宣言することも可能

コロン(:)とセミコロン(;)

 次に、図1-dに含まれるif文を見てみよう。それを抜き出したのがリスト12-7である。

Python
epoch = 100
# 上の行は下記コードの実行に必要な仮のコード

if epoch % 100 == 0: print('')
リスト12-7 コロン「:」の後に改行せずに単純文を記載した例

 この文が1行で記載されているのが「おかしい」と感じたのであれば鋭い。ここまでの説明どおり、if文のコロン:の後は改行してブロックを形成すべきである。しかしながら、このコード例では改行がなされずに、print('')(=空行を出力することで改行している)という文が続いている。

 実は、コロン:は「文の終わり」を意味し、その後に1文(単純文と呼ぶ)を続けて書くことが許容されている。通常は、これまでに示した例のように、改行してからブロックを形成すべきではあるが、1行で書いた方が読みやすくなるような場面では、リスト12-7のように書いてもよいのである。eleifelseを続けて複数行になる場合は、従来どおり改行してからブロックを作ることが推奨される。

 ちなみに、「文の終わり」を意味するキーワードとしては、セミコロン;も用意されている。単純文の最後にセミコロン;を付けることで、別の単純文を記載できる。セミコロン;で続けていけば、1行内に複数の単純文(これを複合文と呼ぶ)を記載することが可能だ。リスト12-8はその例で、通常の関数呼び出しを複合文にすることもできる。

Python
print('1'); print('2'); print('3')

# 1
# 2
# 3 と出力される
リスト12-8 セミコロン「:」の後に複合文を続ける例

 ただし、これはあくまで許容されているだけであって、推奨はされてはいないことに注意してほしい。if文の後を複合文にすることもできるが、非推奨とされている。要するに、このセミコロン;もできるだけ使わないことが推奨される。「同じようなコードが大量に繰り返されるので、改行をなくしてコードの視認性を高めたい」といった特別な理由があるケースでのみ使うべきである。

つづく

 以上、「制御構文(条件分岐)」を説明した。続けて次回は、「制御構文(ループ処理)」を説明する。

  • このエントリーをはてなブックマークに追加

※以下では、本稿の前後を合わせて5回分(第6回~第10回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載目次]を参照してください。

機械学習 & ディープラーニング入門(Python編)[Lesson 9]
6. データ型(リスト/タプル/辞書/各種オブジェクト) ― Python基礎文法入門

Python言語の文法を、コードを書く流れに沿って説明していく連載。前回と今回は、値やデータの型を説明。今回はその後編として、list型/tuple型/dict型、それら以外のオブジェクトの型を取り上げる。

2019年2月18日(月)
機械学習 & ディープラーニング入門(Python編)[Lesson 9]
7. 関数 ― Python基礎文法入門

Python言語の文法を、コードを書く流れに沿って説明していく連載。今回は、プログラム内の各処理を実現する関数について説明する。また、関連事項として、文字列フォーマット関数についても言及する。

2019年3月1日(金)
機械学習 & ディープラーニング入門(Python編)[Lesson 9]
8. 関数の定義 ― Python基礎文法入門

Python言語の文法を、コードを書く流れに沿って説明していく連載。前回に続けて、今回は関数の定義方法を説明する。加えて、デフォルト引数やキーワード引数という重要機能、Python言語で特徴的なインデントについても説明する。

2019年3月25日(月)
機械学習 & ディープラーニング入門(Python編)[Lesson 9]
9. 【現在、表示中】≫ 条件分岐 ― Python基礎文法入門

Python言語の文法を、コードを書く流れに沿って説明していく連載。今回は制御構文のうち、条件分岐について説明する。ロジックや処理フローを定義するための大事な文法である。

2019年4月8日(月)
機械学習 & ディープラーニング入門(Python編)[Lesson 9]
10. ループ処理 ― Python基礎文法入門

Python言語の文法を、コードを書く流れに沿って説明していく連載。今回は前回に引き続き、制御構文を取り上げ、そのうちのループ処理について説明する。繰り返し処理を実装するための大事な文法である。

2019年5月10日(金)
Deep Insider の SNS :

本コンテンツの目次

機械学習 & ディープラーニング入門(Python編)[Lesson 9]
機械学習 & ディープラーニング入門(Python編)[Lesson 9]

条件分岐 ― Python基礎文法入門


本コンテンツに関連する重要用語