【Python】例外処理をジャンケンで使ってみる

#書くこと
Pythonでジャンケンアプリのミニアプリを作成しました。

今回書くのは
その時に引っかかった、**「例外処理」**について

#環境
Python 3.9.2

#例外処理とは
wikiを参照すると

>システムの設計で想定されておらず、ユーザー操作によって解決できない問題に対処するための処理である。

と書かれていますが、よくわからないのでもう少し噛み砕くと

https://twitter.com/BartleySaito/status/1376349292076486659


>文法的には正しいけど、システム的にまずいから、対応できるように書く処理

といった感じでしょうか。
ちなみに文法を間違えていると、構文エラーという定義になります。
(参考: [Pythonの例外処理！try-exceptをわかりやすく解説！](https://www.**.net/blog/23044))

##課題としたこと
さて、ざっくり例外処理がわかったところで早速僕の引っかかったところを説明します。

[完成したソースコードはこちら（）]

まずは、ソースコードをご覧下さい。

```junken.py
print("0: グー, 1: チョキ, 2: パー")

#ジャンケンの手を配列に
junkens = ["グー", "チョキ", "パー"]

#プレイヤーの手を、数字として変数に代入
my_hand = input("最初はグー、ジャンケン...")    

#my_handを用いて、junkens配列から手を取得
my_result = junkens[int(my_hand)]

#my_result(＝プレイヤーの手)を出力
print(my_result)
```

さて、ここで考えられる例外として、

####「ユーザーが、0, 1, 2以外を入力する」
が考えられます。
これに対応するにはどうすればいいかということを課題に抱えました。

例えば、数字の3を入力されると、例外と判定されます。
つまり、文法的に間違っているのではなく、用意しているシステム的にまずい状態です。
(配列には、インデックスとして0~2しか用意していないため)

このままだと、**例外が起きた時点で処理が止まります。**

それだと使ってくれる人に申し訳ないので、止まらないように別の処理を作っておきましょう。
この処理が、**例外処理**です。

##具体的な記述
では、どのように解決したか

以下のソースコードのように改変しました。

```junken.py

print("0: グー, 1: チョキ, 2: パー")

#ジャンケンの手を配列に
junkens = ["グー", "チョキ", "パー"]

#プレイヤーの手を変数に代入
#0~2以外の入力＝例外が行われた時の処理を記述
while True:  
  try:                                               #例外ではない時の処理
    my_hand = input("最初はグー、ジャンケン...")    
    my_result = junkens[int(my_hand)]
    break
  except IndexError:                                 #例外が発生した時の処理1
    print("0~2の数字を入力してください")   
  except ValueError:                                 #例外が発生した時の処理2
    print("数字を入力してください")

```
このように、`try`と`except`を用いて例外処理を構築しました。
つまり

- **例外が起きない場合（＝入力が0~2の整数）である場合、**先ほどのように変数に代入。
- **例外が起きた場合1 （＝入力が0~2の整数以外）である場合、**文字列を出力した後に、もう一度tryの処理を実行
- **例外が起きた場合2（=何も入力されなかった場合）、**文字列を出力した後に、もう一度tryの処理を実行 

このようにして、例外処理を作成することで、例外が起きても処理が止まることを防ぐことができるようになりました。

##完成品（一応動きますが、コピペはオススメしません）

```junken.py
import random

print("0: グー, 1: チョキ, 2: パー")

#ジャンケンの手を配列に
junkens = ["グー", "チョキ", "パー"]

#プレイヤーの手を変数に代入
#0~2以外の入力＝例外が行われた時の処理を記述
while True:  
  try:                                               #例外ではない時の処理
    my_hand = input("最初はグー、ジャンケン...")    
    my_result = junkens[int(my_hand)]
    break
  except IndexError:                                 #例外が発生した時の処理1
    print("0~2の数字を入力してください")   
  except ValueError:                                 #例外が発生した時の処理2
    print("数字を入力してください")

#コンピュータ側の手を変数に代入
computer_hand = random.randint(0,2)
computer_result = junkens[int(computer_hand)]
  
#勝敗を判断させるメソッドを定義
def judge(my_hand, computer_hand):
  if int(my_hand) == computer_hand:
    result = "あいこです"
  elif int(my_hand) == 0 and computer_hand == 1:
    result = "勝ちです"
  elif int(my_hand) == 1 and computer_hand == 2:
    result = "勝ちです"
  elif int(my_hand) == 2 and computer_hand == 0:
    result = "勝ちです"
  else:
    result = "負けです"

  return result

print("あなたの手: " + my_result)
print("相手の手: " + computer_result)

print(judge(my_hand, computer_hand))
````

はい、このように1vs1のジャンケンアプリを作成することができました。

#最後に
最後まで読んでいただき、ありがとうございます。
ソースコード、記事の書き方について「もっとこうしたほうがいいよ！」というご意見、「そこどうなっているの？」というご質問など、お待ちしております。

#参考文献
- [Pythonの例外処理！try-exceptをわかりやすく解説！](https://www.**.net/blog/23044)
- [Pythonチュートリアル 「8. エラーと例外」](https://docs.python.org/ja/3/tutorial/errors.html)