Python3 のエラーと例外
Python 初心者が初めて Python プログラミングを学習する場合、これまで触れていなかったエラー メッセージがよく表示されますが、この章では具体的に説明します。
Python には、構文エラーと例外という、見つけやすい 2 種類のエラーがあります。
Python のアサートは、式を評価し、式の条件が false の場合に例外をトリガーするために使用されます。
文法上の誤り
次の例に示すように、Python の構文エラー、つまり解析エラーは初心者がよく遭遇します。
>>> while True print('Hello world')
File "<stdin>", line 1, in ?
while True print('Hello world')
^
SyntaxError: invalid syntax
この例では、関数print()の前にコロン:が欠落しているため、エラーがチェックされます。
パーサーは問題の行をポイントし、最初に見つかったエラーを小さな矢印でマークします。
異常な
Python プログラムの構文が正しい場合でも、実行時にエラーが発生する場合があります。実行時に検出されるエラーは例外と呼ばれます。
ほとんどの例外はプログラムによって処理されず、ここにエラー メッセージとして表示されます。
>>> 10 * (1/0) # 0 不能作为除数,触发异常
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ZeroDivisionError: division by zero
>>> 4 + spam*3 # spam 未定义,触发异常
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2 # int 不能与 str 相加,触发异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
例外はさまざまなタイプで発生し、メッセージの一部として出力されます。この例のタイプは、ZeroDivisionError、NameError、および TypeError です。
エラー メッセージの最初の部分には、例外が発生したコンテキストが示され、コール スタックの形式で特定の情報が表示されます。
例外処理
試す/除外する
例外キャッチにはtry/Exceptステートメントを使用できます。
次の例では、ユーザーは有効な整数を入力できますが、プログラムを中断することもできます (Control-C またはオペレーティング システムが提供するメソッドを使用)。ユーザーが中断した情報により、KeyboardInterrupt 例外が発生します。
while True:
try:
x = int(input("请输入一个数字: "))
break
except ValueError:
print("您输入的不是数字,请再次尝试输入!")
try ステートメントは次のように機能します。
- まず、try 節 (キーワード try とキーワードexcel の間の文) が実行されます。
- 例外が発生しない場合は、Except 句は無視され、try 句が実行されて終了します。
- try 句の実行中に例外が発生した場合、try 句の残りの部分は無視されます。例外の種類が、Except の後の名前と一致する場合、対応するExcept 句が実行されます。
- 例外がどの例外とも一致しない場合、例外は上位の try に渡されます。
try ステートメントには、さまざまな特定の例外を処理するための複数のException 句が含まれる場合があります。最大 1 つのブランチが実行されます。
ハンドラーは、対応する try 句の例外のみを処理し、他の try ハンドラーの例外は処理しません。
例外句は複数の例外を同時に処理できます。これらの例外は括弧内に置かれてタプルを形成します。次に例を示します。
except (RuntimeError, TypeError, NameError):
pass
最後の例外句では、ワイルドカードとして使用される例外名を無視できます。このメソッドを使用すると、エラー メッセージを出力し、再度例外をスローできます。
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise
試す/除く...その他
try/excelステートメントにはオプションのelse句もあります。この句を使用する場合は、すべてのelse句の後に配置する必要があります。
else句は、 try句で例外が発生しなかった場合に実行されます。次の例では、 try
ステートメントでファイルを開くことができるかどうかを判断します。ファイルを開くときに例外が発生しない場合は、ステートメントのelse部分が実行され、ファイルの内容が読み取られます。
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except IOError:
print('cannot open', arg)
else:
print(arg, 'has', len(f.readlines()), 'lines')
f.close()
すべてのステートメントをtry句に入れるよりもelse句を使用する方が良いため、 Except がキャッチできない予期しない例外を回避できます。
例外処理は、 try句内で直接発生する例外を処理するだけでなく、句内で呼び出される関数 (間接的に呼び出される関数も含む) でスローされた例外も処理します。例えば:
>>> def this_fails():
x = 1/0
>>> try:
this_fails()
except ZeroDivisionError as err:
print('Handling run-time error:', err)
Handling run-time error: int division or modulo by zero
try-finally ステートメント
try-finally ステートメントは、例外が発生したかどうかに関係なく、最後のコードを実行します。
次の例では、例外が発生したかどうかに関係なく、finally ステートメントが実行されます。
try:
runoob()
except AssertionError as error:
print(error)
else:
try:
with open('file.log') as file:
read_data = file.read()
except FileNotFoundError as fnf_error:
print(fnf_error)
finally:
print('这句话,无论异常是否发生都会执行。')
例外をスローする
Python は、raise ステートメントを使用して、指定された例外をスローします。
raise の構文形式は次のとおりです。
raise [Exception [, args [, traceback]]]
次の例では、x が 5 より大きい場合に例外をトリガーします。
x = 10
if x > 5:
raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
上記のコードを実行すると例外がトリガーされます。
Traceback (most recent call last):
File "C:\Users\Lenovo\Desktop\test.py", line 3, in <module>
raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
Exception: x 不能大于 5。x 的值为: 10
発生させる唯一の引数は、スローされる例外を指定します。これは、例外または例外クラス (つまり、Exception のサブクラス) のインスタンスである必要があります。
例外がスローされたかどうかを知りたいだけで、それを処理したくない場合は、単純な raise ステートメントで例外を再度スローできます。
>>> try:
raise NameError('HiThere') # 模拟一个异常。
except NameError:
print('An exception flew by!')
raise
An exception flew by!
Traceback (most recent call last):
File "<stdin>", line 2, in ?
NameError: HiThere
ユーザー定義の例外
新しい例外クラスを作成することで、独自の例外を設定できます。例外クラスは Exception クラスを継承し、直接的または間接的に継承できます。次に例を示します。
>>> class MyError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
>>> try:
raise MyError(2*2)
except MyError as e:
print('My exception occurred, value:', e.value)
My exception occurred, value: 4
>>> raise MyError('oops!')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
__main__.MyError: 'oops!'
この例では、クラス Exception のデフォルトの _ init _() がオーバーライドされます。
多くの異なる例外をスローする可能性のあるモジュールを作成する場合、一般的なアプローチは、パッケージの基本例外クラスを作成し、次にこの基本クラスに基づいてさまざまなエラー条件に対応するさまざまなサブクラスを作成することです。
class Error(Exception):
"""Base class for exceptions in this module."""
pass
class InputError(Error):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
class TransitionError(Error):
"""Raised when an operation attempts a state transition that's not
allowed.
Attributes:
previous -- state at beginning of transition
next -- attempted new state
message -- explanation of why the specific transition is not allowed
"""
def __init__(self, previous, next, message):
self.previous = previous
self.next = next
self.message = message
ほとんどの例外名は、標準の例外名と同様に「Error」で終わります。
クリーンアップ動作を定義する
tryステートメントには、状況に関係なく実行されるクリーンアップ動作を定義するオプションの句もあります。例えば:
>>> try:
... raise KeyboardInterrupt
... finally:
... print('Goodbye, world!')
...
Goodbye, world!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
KeyboardInterrupt
上記の例では、try句で例外が発生したかどうかに関係なく、 finally句が実行されます。
try句 (または、Except 句、またはelse句)で例外がスローされ、例外がキャッチされなかった場合、その例外は、finally句が実行された後にスローされます。
次に、より複雑な例を示します (同じtryステートメント内に、 Except句とFinal句が含まれています)。
>>> def divide(x, y):
try:
result = x / y
except ZeroDivisionError:
print("division by zero!")
else:
print("result is", result)
finally:
print("executing finally clause")
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
事前定義された清掃動作
一部のオブジェクトでは標準のクリーンアップ動作が定義されており、システムがそれを正常に使用するかどうかに関係なく、オブジェクトが不要になると、この標準のクリーンアップ動作が実行されます。
次の例は、ファイルを開いてその内容を画面に出力しようとする例を示しています。
for line in open("myfile.txt"):
print(line, end="")
上記のコードの問題は、実行後、ファイルが開いたままになり、閉じられないことです。
キーワードwithステートメントを使用すると、ファイルなどのオブジェクトが使用後にクリーンアップ メソッドを正しく実行することを保証できます。
with open("myfile.txt") as f:
for line in f:
print(line, end="")
上記のコードを実行すると、処理中に問題が発生した場合でも、ファイル f は常に閉じられます。
キーワード付き
Pythonのwithステートメントは例外処理に使用され、try...excel...finallyコーディング パラダイムをカプセル化し、使いやすさを向上させます。
withステートメントを使用すると、コードがより明確で読みやすくなり、ファイル ストリームなどのパブリック リソースの管理が簡素化されます。
ファイル オブジェクトを操作する場合は、withキーワードを使用することをお勧めします。
次のコード例を見てみましょう: with は
使用せず、try...excel...finally も使用しないでください。
file = open('./test.txt', 'w')
file.write('hello world !')
file.close()
上記コードの書き込み呼び出し中に例外が発生した場合、close メソッドは実行されないため、リソースは常にプログラムによって占有され、解放できません。次に、try...excel...finally を使用してコードを改善します。
file = open('./test.txt', 'w')
try:
file.write('hello world')
finally:
file.close()
上記のコードでは、例外が発生する可能性のあるコードをキャプチャしようとしています。例外が発生すると、excel コード ブロックが実行されます。どのような状況であっても、finally コード ブロックが実行されるため、ファイルは閉じられ、リソースは解放されます。実行例外により占有されません。
withキーワードを使用します。
with open('./test.txt', 'w') as file:
file.write('hello world !')
withキーワードを使用すると、システムは自動的にf.close()メソッドを呼び出します。withの機能はtry/finally ステートメントと同等です。
withキーワードを実行した後にファイルが閉じられているかどうかを確認できます。
>>> with open('./test.txt') as f:
... read_data = f.read()
>>> # 查看文件是否关闭
>>> f.closed
True
withステートメントの実装原則は、コンテキスト マネージャーに基づいています。
コンテキスト マネージャーは、 enter メソッドとexitメソッドを実装するクラスです。
with ステートメントを使用して、ネストされたブロックの最後でexitメソッドが確実に呼び出されるようにします。
この概念は、try...finallyブロックの使用に似ています。
with open('./test.txt', 'w') as my_file:
my_file.write('hello world!')
上の例では、hello world! を ./test.txt ファイルに書き込みます。
_ enter _ メソッドと _ exit _ メソッドは file オブジェクトで定義されています。つまり、ファイル オブジェクトはコンテキスト マネージャーも実装しています。最初に _ enter _ メソッドが呼び出され、次にwithステートメント内のコードが実行され、最後に_ exit _ メソッドが呼び出されます。エラーが発生した場合でも、 exitメソッドが呼び出されます。これは、ファイル ストリームが閉じられることを意味します。
主張する
Python のアサートは、式を評価し、式の条件が false の場合に例外をトリガーするために使用されます。
アサーションは、プログラムの実行条件が満たされないときに、実行後にプログラムがクラッシュするのを待つことなく、直接エラーを返すことができます。たとえば、コードは Linux システムでのみ実行でき、最初に、現在のシステムは条件を満たしています。
構文形式は次のとおりです。
assert expression
に相当:
if not expression:
raise AssertionError
assert の後にパラメータを続けることもできます。
assert expression, [arguments]
に相当:
if not expression:
raise AssertionError(arguments)
以下はアサートの使用例です。
>>> assert True # 条件为 true 正常执行
>>> assert False # 条件为 false 触发异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
>>> assert 1==1 # 条件为 true 正常执行
>>> assert 1==2 # 条件为 false 触发异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
>>> assert 1==2, '1 不等于 2'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: 1 不等于 2
>>>
次の例では、現在のシステムが Linux であるかどうかを判断します。条件が満たされない場合は、次のコードを実行せずに例外が直接トリガーされます。
import sys
assert ('linux' in sys.platform), "该代码只能在 Linux 下执行"