Python 例外処理

Python学習【365日チャレンジ!】64日目のマスターU(@Udemy11)です。

exception(エクセプション)という名前で、ディカプリオ主演で渡辺謙が出演している映画を思い出しました。

映画の題名は、エクセプションではなく、インセプション(Inception)なんですけど。。。

キアヌ・リーブス主演のマトリックスみたいな感じがしなくもない映画なんですが、人の深層記憶を操るために、他人の意識に侵入して仮想空間と現実を行き来するので、結構頭を使います。

個人的には結構好きなジャンルで、なかなかおもしろかった記憶があります。

いや〜それにしても、若いですね、渡辺謙!

話はとんじゃいますが、Udemyで春の新学期セールが始まっています。

自宅にいることが多くなると思いますので、この機会にぜひ、Udemyの講座を受講してみてください。

↓公式サイトはこちら↓
UdemyセールUdemyセール

それでは、今日もPython学習をはじめていきましょう!

昨日の復習

昨日は、名前空間とスコープを学習しました。

名前空間とスコープって同じようなものですが、微妙に違います。
ただ特にその違いを理解していなくても普通にPythonを使うことができるので、きちんと理解しておく必要はありませんが、こんなものがあるということは知っておいたほうがいいでしょう。

fruits = 'apple'

def f():
    fruits = 'banana'
    print(fruits)

f()
print(fruits)

出力結果

banana
apple

Pythonの中にある名前空間には、グローバルとローカルとがあって、それぞれのエリアで宣言された変数が有効となる範囲がスコープでした。

global変数のスコープは、localエリアも含まれるので、localエリアでglobal変数は使えますが、同じ名前のlocal変数があるとローカル変数のほうが優先されます。

また、local変数は、globalエリアでは利用できませんでした。

詳しくは昨日のエントリーで復習してください。

今日は、例外処理について学習します。

例外処理

例外処理は、期待される通常の動作以外の例外が起こったときの処理のことです。

Pythonに限らず、プログラムでエラーが起こると実行が途中で止まったり、処理をし続けるようなことになります。

そんな例外をきちんと処理して、プログラムの実行を完了させるために必要なのが例外処理です。

例えば、リストに値を入れて、インデックスの位置から値を抽出するコードを書いたとしましょう。

l = [1, 2, 3, 4]
i = 5
print(l[i])

このコードの場合、次のようなエラーが起こります。

IndexError: list index out of range

Pythonからインデックスが5の値は、範囲の中にありませんよ!と怒られているわけですね。

このエラーを回避するために使うのが例外処理です。

try-except文

上記の例で、エラーが起こったときに、エラーでプログラムを中断させないようにするには、try文とexcept文をあわせて利用します。

l = [1, 2, 3, 4]
i = 5

try:
    print(l[i])
except:
    print('No problem')

出力結果

No problem

print(l[i])を実行してみて、エラーが起こったときは、exceptを実行するコードになるので、結果は、No problemが出力されます。

もちろん、変数iが0〜3であれば、問題なくprint(l[i])が実行されて、exceptは実行されませんので、値だけが出力されます。

他にもprint(l[i])の部分をprint(r[i])などと定義されていない変数を使ってしまった場合でも同じようにNo problemが出力されます。

エラーを指定できる

定義していない変数を使ってしまった場合のエラーは、NameErrorで、存在しないインデックスを指定したときはIndexErrorです。

他にもいろいろなエラーがありますが、すべてのエラーはこちらの公式ドキュメントから確認することが可能です。

except文は、このエラーの中から特定のエラーが起こったときに処理をさせることも可能です。

l = [1, 2, 3, 4]
i = 5

try:
    print(l[i])
except IndexError:
    print("Don't worry about it.")

出力結果

Don't worry about it.

この例では、インデックスエラーが起こったときにDon't worry about itと出力されますが、NameErrorの場合はエラーでプログラムが中断します。

もちろん、エラーを指定せずにexceptだけで処理をさせるとSyntaxError以外はほとんどカバーできるみたいですが、影響のないエラーのときだけ処理を中断させずにプログラムを完了させたいという使い方はできません。
人間で言うところの、怪我をしているのに痛みを感じさせずに作業をさせるような薬を使っているのと同じようなものでしょうか。(ちょっと例えが分かりづらい?)

なので、決まったエラーだけは例外処理をして、プログラムを完了させたい場合は、エラーを指定してプログラムを完了させます。

また、どんなエラーが起こっているのか表示させるためには次のような使い方もできます。

l = [10, 20, 30]
i = 3

try:
    l[i]
except IndexError as ex:
    print('Error is {}'.format(ex))

出力結果

Error is list index out of range

IndexErrorが起きたときのみ、asを使って変数exにエラー文を代入し、formatメソッドを使ってエラー文を出力したあと、プログラムを完了します。

except文は、続けて記述することが可能で、いくつかのエラーをキャッチして、エラー文を出力させることができます。

l = [10, 20, 30]
i = 3

try:
    r[i]
except IndexError as ex:
    print('Error : {}'.format(ex))
except NameError as ex:
    print('Error : {}'.format(ex))

このコードの場合は、Error : name 'r' is not definedと表示されます。

Exceptionを指定

私みたいなPython学習者の場合、どんなエラーが起こっているのか出力させて、プログラムはきちんと完了すればいいんじゃないの?と思っちゃうのですが、これから紹介する使い方は推奨されていないので、こんなことができるとだけ憶えておいてください。

i = 1

try:
    print(a)
except Exception as ex:
    print('Error : {}'.format(ex))

上記で紹介しているPythonの公式ドキュメントには、エラーコードがたくさん紹介されていますが、エラーであるExceptionにはたくさんの種類があるので、エラーにExceptionを指定して、エラー文を出力させるようにしておけば、プログラムを中断させずにどんなエラーが起こったのかがわかります。

ただ、最初に紹介したように、このような使い方は推奨されていないので、こんなこともできるとだけ憶えておきましょう。

finally文の使い方

エラーが起こる起こらないに関わらず、最後に処理をさせたいときに使うのがfinally文です。

l = 10
i = 3

try:
    l[i]
except IndexError as ex:
    print('Error : {}'.format(ex))
except NameError as ex:
    print('Error : {}'.format(ex))
finally:
    print('Clean up')

このコードの場合、TypeErrorを返してプログラムは中断しますが、中断する前にClean upを出力します。

正常にプログラムが終了したときも最後にClean upが出力されるので、エラーが起こるかどうかに関わらず、必ず実行されるのがfinally文ということです。

else文の使い方

最後に紹介するのがtyr-except-else文です。

tryexceptにつづいてelse文を記述すると、try文での実行が正常に終了した場合のみ、else文が実行されます。

l = [10, 2, 3]

try:
    print(l)
except:
    print('Error occurred')
else:
    print('Finish')
finally:
    print('Clean up')

出力結果

[10, 2, 3]
Finish
Clean up

else文は、try文の実行がきちんと完了しているかどうかを確認したいときに使えますが、それなら一番最後に記述しても同じじゃないの?と思っていまいませんか?

それでもいいんですが、処理が完了するしないに関わらず、最後finally分で何かをしたいときには、else分が使われるようです。

パターンをつかむ

Pythonを学習し始めてから、すでに2ヶ月が過ぎましたが、まだ入り口に差し掛かったくらいでまだまだわからないことだらけだという気持ちと、ある程度パターン的なことがなんとなくつかめてきたかなという気持ちがあります。

学習している内容としては、本当にPythonの入り口で学習することだと思うので、まだまだ学ばないといけないことはたくさんあるわけですが、少しだけパターンがつかめてきたような気はしています。

とはいえ、復習が大切なので、3歩進んで2歩下がるを繰り返しながら、一歩ずつしっかりと進んでいこうと思います。

それでは、明日もGood Python!