試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

Pythonの例外とその処理に関する覚え書き(ユーザ定義の例外など)

Pythonの例外とその処理に関する覚え書き(概要、書式、後始末処理)」に続いて、例外に関して幾つかのことをまとめておく。
(2014/11/13)リンク先を修正し、サンプルコードの内容もPython 3に対応し、本文の記述も一部書き直している。

  1. else節
  2. 例外を起こす
  3. ユーザ定義の例外

else節

例外が発生した場合の処理はexcept節に記述するが、発生しなかったときにだけ行いたい処理がある場合、except節よりも下にelse節を記述することで実行されるようにできる。

try:
  # [失敗して例外名1もしくは例外名2の例外を発生させる可能性のある処理(関数呼び出し)...]
except [例外名1] as [例外オブジェクト1]:
  # [例外名1の例外が発生した場合の処理...]
except [例外名2] as [例外オブジェクト2]:
  # [例外名2の例外が発生した場合の処理...]
# ...
else:
  # [いずれの例外も発生しなかった場合の処理...]

例外を起こす

何かの処理の中で、状況によっては(処理を中止しつつ)例外としてそれを通知したいということがある。そういったときにraise文を用いると任意の例外を「起こす」ことができる。その際には例外への引数を付けることもできる。

raise [例外名] ([引数...])

ユーザ定義の例外

例外として扱いたい状況が発生したとき、定義済みの例外以外に独自の名前を付けて使用したい場合がある。そうしたときにはExceptionクラスを継承した例外クラスを定義することでユーザ定義の例外を作成できる。下は例。上に書いているelse節やraise文も使用している。
[任意]ファイル名: userexceptiontest.py

#! /usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import print_function

import sre_constants
import sys
import re

class PatternNotFoundException (Exception):
  """
  正規表現パターンが見つからないときに発生させる例外
  """
  def __init__ (self, instr, ptn):         # instrとptnはraise文から受け取る引数
    self._instr, self._ptn = (instr, ptn)  # メンバ変数に代入
  def __str__ (self):                      # エラーメッセージ
    return ('Pattern "{0}" not found in "{1}"'.format (self._ptn, self._instr))

class RegexPatternChecker:
  """
  正規表現パターンのチェックを行うツール
  """
  def __init__ (self, ptn):
    self._regexobj = re.compile (ptn)
    self._ptn = ptn
  def check (self, instr):
    """
    入力された文字列を正規表現オブジェクトによりチェックして
    パターンが見つからない場合にPatternNotFoundExceptionを出す
    """
    print ('checking {0} in {1} ... '.format (self._ptn, instr), end='')
    m = self._regexobj.search (instr)
    # 見つからない場合に例外を発生するようにする
    if not m:
      raise PatternNotFoundException (instr, self._ptn)  # 括弧内は引数


# メイン処理
str1 = '<img src="01.jpg" alt="desc" />'
str2 = '<img src="02.jpg" />'
ptnstr = 'alt="[^"]+"'
#ptnstr = '(a'  # 不正なパターン文字列のテスト用

try:
  checker_imgalt = RegexPatternChecker (ptnstr)
except sre_constants.error as e:
  sys.exit ('Invalid regex pattern: "{0}": {1}'.format (ptnstr, e))

# 個別にtry-except-elseでチェックし、結果を表示
try:
  checker_imgalt.check (str1)
except PatternNotFoundException as e:
  print ('BAD\nPatternNotFoundException: {0}'.format (e))
else:
  print ('GOOD')

try:
  checker_imgalt.check (str2)
except PatternNotFoundException as e:
  print ('BAD\nPatternNotFoundException: {0}'.format (e))
else:
  print ('GOOD')

print ('-' * 80)

# try-exceptがないところで例外が発生したらそこで実行が中止される
checker_imgalt.check (str1)
print ('GOOD')
checker_imgalt.check (str2)  # ここで発生
print ('GOOD')

# ここには到達しないため下のメッセージは表示されない
print ('All OK')

(2009/5/25)不正な正規表現パターン文字列が指定された場合の処理を追加
下は実行結果。線を引いた上の最終行ではtry-exceptにより捉えたときに情報を出力している。線の下のほうでは、2番目の文字列(str2)を処理しているときに例外が捉えられていないためそこで(自動的に)例外の情報や発生位置を表示しつつ終了している。

checking alt="[^"]+" in <img src="01.jpg" alt="desc" /> ... GOOD
checking alt="[^"]+" in <img src="02.jpg" /> ... BAD
PatternNotFoundException: Pattern "alt="[^"]+"" not found in "<img src="02.jpg" />"
--------------------------------------------------------------------------------
checking alt="[^"]+" in <img src="01.jpg" alt="desc" /> ... GOOD
checking alt="[^"]+" in <img src="02.jpg" /> ... Traceback (most recent call last):
  File "[userexceptiontest.pyの場所]", line 69, in <module>
    checker_imgalt.check (str2)  # ここで発生
  File "[userexceptiontest.pyの場所]", line 35, in check
    raise PatternNotFoundException (instr, self._ptn)  # 括弧内は引数
__main__.PatternNotFoundException: Pattern "alt="[^"]+"" not found in "<img src="02.jpg" />"

参考URL: