今日は教科書の Lesson 4 の続きなのですが、教科書ではどういうわけか if 〜 else 〜 を飛ばして、if 〜 elif 〜 else しかありません。初学者の人もいるでしょうから、一応押さえておきます。
下図の左側は前回に出したもので、if 文の条件節が False だった時に、if 文の中に書いた処理を「迂回」する構造です。そして右側が今回紹介する「if 文の条件節が True / False それぞの場合に実行すべき処理を置く構造」です。
True / False で処理を分けるのはとても自然なことと思えます。文法状の記述は以下のようになります。
num1 = int(input())
num2 = int(input())
if num1 > num2:
print(num1)
else:
print(num2)
つまり if と同じレベル(インデント位置)に else: を置くと、それ以降が False の場合の処理になります。
教科書ではなぜか if の入れ子構造(ネスティング)も出てきません。ここで押さえておきます。
例えば三つの数のうち一番大きなものを出す、というアルゴリズムは、このようにも書けます。
赤枠は条件分岐(if 文に相当する)が入れ子構造になっていることを示すために付けてみました。
これに相当する if 文の記述は以下(左側)のようになります。インデントによって一段下がったところに True / False の際の実行文が書かれていますが、そこに if 文があると更にもう一段インデントが進むことがわかるでしょう。
右側のコードは同じものなのですが、入れ子構造になっていることを示すために右側に赤枠をつけたものを置いてみました。一つ上の流れ図の構造・赤枠と対照できますね。
これ以降は、教科書の Lesson 4 の続きを進めてください。ただし 4.2, 4.3 だけ、です。それが済めば次の課題に進んでください。
ある年がうるう年か否かを調べるプログラムを作って下さい。うるう年の定義は以下の通りです。
プログラムは実行すると数値を input() で読み取り、その年がうるう年なら “YES”、そうでなければ “NO” を出力するようにしてください。以下のようになるでしょう。
yasuda@Slack 07 % python3 leapyear2.py
2023
NO
yasuda@Slack 07 % python3 leapyear2.py
2024
YES
yasuda@Slack 07 %
まず「割り切れるかどうか」は、剰余演算子 % (教科書 p.42 参照)を使うのが簡単です。例えば変数 year の値が 4 で割り切れることを確認するには以下のようにします。
if year % 4 == 0:
print("割り切れました")
さて、この定義をストレートに流れ図にすると下左図のようになるでしょう。ただ、1, 2, 3 の順をひっくり返して判定すると下右図のようになります。この形は if 〜 elif 〜 else 〜 のパターン(教科書 p.96 参照)ですから、こちらの方が実装したコードはシンプルでわかりやすいものになると想像されます。
また、論理演算子をうまく使えば、以下のような記述で直接的に判定できることがわかるでしょうか。
( year % 4 == 0 ) and ( ( year % 100 != 0 ) or ( year % 400 == 0 ) )
この課題のアルゴリズムや書き方はお任せします。自分にとって扱いやすい方法で作ってください。
プログラムがおおよそ動くようになったら、教材 Web にある leapyear.sh シェルスクリプトを取ってきて、以下のようにして実行してください。(前と同じく、中を見て Python プログラムファイルの名前が違っている場合はエディタで leapyear.sh の中を修正して対応してくださいね。)
yasuda@Slack 07 % zsh leapyear.sh
YES
NO
YES
NO
NO
YES
yasuda@Slack 07 %
結果のパターンが上と同じになっておればひとまず確認としては良いでしょう。Moodle に提出してください。ちゃんとした網羅的なテストについてはまたこの先でやります。
いくつか課題を通して理解度を確認しましょう。
以下のような「じゃんけん」判定プログラムを作成してください。
二つの数を入力として受けて勝敗判定をする
一つ目は「自分の手」、二つ目は「相手の手」
入力は 1, 2, 3 のいずれかで、それぞれグー、チョキ、パーに対応する
勝ち負けは “win”, “lose”, “even” で表示する
教材 Web にひな型になるプログラム janken00.py を置いておきました。ダウンロードして中身を確認し、実行してください。以下のようになるでしょう。
yasuda@Slack 07 % python3 janken00.py
1
2
win
yasuda@Slack 07 %
このプログラムは(中を見るとわかりますが)変数 me, you にデータを読み込み、無条件に “win” と出力します。あなたは正しく勝ち負け判定ができるようにコードを追加し、このプログラムを完成させてください。
つまりアルゴリズムをどうするか、はなかなか考え所だと思います。すべての入力の組み合わせ(一人が出す手が 3 通りで、それが二人ですから 3*3 の 9 通りです。単純に考えられるアルゴリズムを列挙してみます。
様々な方法があると思います。
あたりのことに気をつけて作業してください。
プログラムがおおよそ動くようになったら、教材 Web にある janken.sh シェルスクリプトを取ってきて、以下のようにして実行してください。(これのも必要なら janken.sh の中を修正して対応してください。)
yasuda@Slack 07 % zsh janken.sh
even
even
even
win
win
win
lose
lose
lose
yasuda@Slack 07 %
これで結果が even, win, lose の順で3回ずつ表示されれば判定処理は正しくできています。Moodle に提出してください。
いろいろとエレガントな方法があり得ます。これが良い、と思えるアルゴリズムと記述で提出してください。
実数の判定処理については誤差を意識する必要があります。実数処理における誤差 を見て下さい。
うるう年判定のところで出した論理演算子を用いた条件式の例を出しました。
( year % 4 == 0 ) and ( ( year % 100 != 0 ) or ( year % 400 == 0 ) )
記述が長くなった場合は、適度に折り返してコードを書いておいた方が分かりやすい場合があります。p.19 にもありましたが、「 (バックスラッシュ)」を行末に置くことで次の行に続いていることを示します。以下に例を出します。
if ( year % 4 == 0 ) and ( ( year % 100 != 0 ) or ( year % 400 == 0 ) ):
↓↓↓↓↓ 下のように折り返して書ける
if ( year % 4 == 0 ) and \
( ( year % 100 != 0 ) or ( year % 400 == 0 ) ):
バックスラッシュを使って折り返した次の行のインデント位置はどこでも構いません。
# 上の例よりは大きくインデントをつけてみた。これでも良い。
if ( year % 4 == 0 ) and \
( ( year % 100 != 0 ) or ( year % 400 == 0 ) ):
# 隙間を空けず左端から書いても問題はない。見づらいが。。
if ( year % 4 == 0 ) and \
( ( year % 100 != 0 ) or ( year % 400 == 0 ) ):
バックスラッシュで分割した二行を単純につないで解釈されるだけですから、上の例でいくと「and」と、その後の空白一つ、次の行の先頭の空白三つで「 ( 」です。下に接続し直した状態を示します。
if ( year % 4 == 0 ) and \
( ( year % 100 != 0 ) or ( year % 400 == 0 ) ):
↓↓↓↓↓ 下のように接続した状態で解釈される
if ( year % 4 == 0 ) and ( ( year % 100 != 0 ) or ( year % 400 == 0 ) ):