ホームページ  >  記事  >  バックエンド開発  >  Pythonの例外メカニズムを理解する

Pythonの例外メカニズムを理解する

coldplay.xixi
coldplay.xixi転載
2021-03-10 10:00:332885ブラウズ

前書き: 以前仕事をしていたとき、シリアル ポートを使用して SCPI を送信し、マイクロコントローラーと対話するコマンド ライン ウィンドウを Python を使用して完成させていました。実際に関数を実装してみると、データ処理にはPythonを使用しており、最終的に正しい値が返されるか、エラー値が返されるか、結果を直接メインインターフェースに返すことができます。明らかに、異なる意味を持つデータを直接返すことはできないため、間違った値を持つデータを処理するために例外メカニズムが使用されます。これまでアノマリーについてあまり知らなかったので、ここでいくつかの情報を確認し、いくつかのメモをまとめました。

Pythonの例外メカニズムを理解する

#記事ディレクトリ

    1. 例外の理解
  • #1. 例外とは何ですか?
      ##2. エラーと例外の違い
    • ##3. 一般的な Python 例外の種類
    • # #2. Python の 5 つの主要な例外処理メカニズム
  • 1. デフォルトの例外処理メカニズム
  • 2. try....excel.... 処理メカニズム
    • 3. try...以外...finally.... 処理メカニズム
    • 4. アサーション アサーション処理メカニズム
    • 5. with...as 処理メカニズム
    • 3. Python 例外のカスタマイズ
  • 1.例外のカスタマイズ
  • 2.例外スロー raise
    • 3. 例外のキャッチ
    • #4. 例外を使用する際の注意事項
  • 1. 例外のメカニズムに頼りすぎないでください
  • 2. try ブロックにあまりにも多くのコードを導入しないでください
    • 3. キャッチした例外を無視しないでください
    • 概要
  • (無料学習の推奨事項:

Python ビデオ チュートリアル

) 1. 例外の理解

1. 異常とは

異常とは「正常とは異なる」という意味ですが、正常とは何でしょうか? 「正常」とは、インタプリタがコードを解釈するときに、作成したコードがインタプリタによって定義されたルールに準拠しており、正常であることを意味します。インタプリタが、

特定のコードは文法に準拠しているが、異常である可能性があると判断した場合 の場合、インタプリタはプログラムの通常の実行を中断するイベントを発行します。この割り込み信号は Exception 信号

です。したがって、

全体の説明は、インタプリタがプログラムのエラーを検出すると例外が発生し、プログラムがそれを処理しない場合は例外をスローしてプログラムを終了するということになります。空の .py ファイルに int ("m") を書き込むと、実行後の結果は次のようになります。 int() で渡されるパラメータは数値文字列と数字のみをサポートしているため、このフォント文字列はインタープリタによってスローされる一連のエラー メッセージです。入力文字列パラメータが間違っているため、インタープリタは「valueError」エラーを報告します。
2. エラーと例外の違いPythonの例外メカニズムを理解する

Python エラーの概要:

コードが実行される前の構文エラーまたは論理エラーを指します

。通常の構文エラーを例に挙げると、作成したコードが構文テストに合格できない場合、直接構文エラーが表示されます。プログラムを実行する前にそれを修正する必要があります。そうでないと、記述したコードは無意味になり、コードは実行されません。となり、キャプチャできなくなります。たとえば、.py ファイルに a = 1 print("hello") が入力された場合、出力結果は次のようになります。

  Traceback (most recent call last):
  	File "E:/Test_code/test.py",line 1
    	if a = 1 print("hello")
                ^SyntaxError: invalid syntax
関数 print() にエラーが見つかりました。その前にコロンがありません: 、そのため、パーサーは構文エラーのあるコード行を再現し、小さな「矢印」を使用して行内で検出された最初のエラーを指すため、対応する位置を直接見つけることができます。そしてその構文を変更します。もちろん、文法エラーに加えて、メモリ オーバーフローなどのプログラム クラッシュ エラーも多数あります。このようなエラーは比較的隠蔽されることがよくあります。

エラーと比較すると、

Python 例外は主にプログラムの実行中にプログラムが論理的またはアルゴリズムの問​​題に遭遇したときに発生します インタプリタが処理できる場合は問題ありませんが、処理できない場合はこの場合、プログラムは直接終了されます。パラメータが正しく渡されないため、最初のポイントの int('m') の例のように例外がスローされ、プログラム エラーが発生します。ロジックによって引き起こされる例外にはさまざまな種類がありますが、幸いなことに、インタープリタにはさまざまなタイプの例外が組み込まれており、どのような例外が発生するかを知ることができるため、「適切な薬を処方する」ことができます。 ここで注意すべき点は、上記の構文エラーは識別可能なエラーであるため、インタプリタもデフォルトで SyntaxError 例外メッセージをスローしてプログラマにフィードバックすることです。したがって、本質的に、ほとんどのエラーは出力および表示できますが、エラー コードが実行されないため処理できないため、エラー例外情報のキャプチャは無意味になります。


3. 一般的な Python 例外の種類
コードを記述するときに最も一般的な例外の種類は次のとおりです。他の種類の例外が発生した場合は、もちろん白を選択してください時間です~

#例外名名前解決BaseExceptionすべての例外 Base classSystemExit終了へのインタープリタ要求KeyboardInterruptユーザーが実行を中断します (通常は ^ を入力します) C)Exception一般エラー基本クラスStopIterationイテレータなしその他の値GeneratorExitジェネレーターは、終了に通知する例外を生成します。#StandardErrorすべてのビルドの基本クラス-in 標準例外##ArithmeticErrorFloatingPointError OverflowErrorZeropisionErrorAssertionError##AttributeError オブジェクトはこの属性を持っていますEOFError組み込み入力がありません。EOF フラグに達しましたEnvironmentError オペレーティング システム エラーの基本クラスIOError入出力操作が失敗しましたOSErrorOperatingシステム エラーWindowsErrorシステム コールに失敗しましたImportErrorモジュール/オブジェクトのインポートに失敗しましたLookupError無効なデータ クエリ 基本クラスIndexErrorIn sequence No such Index(index)KeyErrorマップ内にそのようなキーはありませんMemoryErrorメモリ オーバーフロー エラー (そうではありません) Python インタプリタにとって致命的)未宣言/初期化オブジェクト (属性なし)初期化されていないローカル変数へのアクセス弱い参照がガベージ コレクションされたオブジェクトにアクセスしようとしています一般的なランタイム エラーまだメソッドが実装されていません構文エラーインデント エラースペースが混在しています#SystemError一般的なインタープリタ システム エラー##ValueError無効なパラメータが渡されましたUnicodeError Unicode関連エラー UnicodeDecodeError Unicodeデコード中のエラーUnicodeEncodeError UnicodeUnicodeTranslateError UnicodeWarningDeprecationWarningFutureWarningOverflowWarning PendingDeprecationWarningRuntimeWarningSyntaxWarningUserWarning#

二、python五大异常处理机制

  我们明白了什么是异常后,那么发现异常后怎么处理,便是我们接下来要解决的问题。这里将处理异常的方式总结为五种。

1、默认异常处理机制

  “默认”则说明是解释器默认做出的行为,如果解释器发现异常,并且我们没有对异常进行任何预防,那么程序在执行过程中就会中断程序,调用python默认的异常处理器,并在终端输出异常信息。刚才举过的例子:int(“m”),便是解释器因为发现参数传入异常,这种异常解释器“无能为力”,所以它最后中断了程序,并将错误信息打印输出,告诉码农朋友们:你的程序有bug!!!

2、try…except…处理机制

  我们把可能发生错误的语句放在try语句里,用except来处理异常。每一个try,都必须至少有一个或者多个except。举一个最简单的例子如下,在try访问number的第500个元素,很明显数组越界访问不了,这时候解释器会发出异常信号:IndexError,接着寻找后面是否有对应的异常捕获语句except ,如果有则执行对应的except语句,待except语句执行完毕后,程序将继续往下执行。如果没有对应的except语句,即用户没有处理对应的异常,这时解释器会直接中断程序并将错误信息打印输出

number = 'hello'try:	print(number[500])	#数组越界访问except IndexError:	print("下标越界啦!")except NameError:	print("未声明对象!")print("继续运行...")

输出结果如下,因为解释器发出异常信号是IndexError,所以执行下标越界语句。

下标越界啦!
继续运行...

  为了解锁更多用法,我们再将例子改一下,我们依然在try访问number的第500个元素,造成访问越界错误,这里的except用了as关键字可以获得异常对象,这样子便可获得错误的属性值来输出信息。

number = 'hello'try:	print(number[500])	#数组越界访问except IndexError as e:	print(e)except Exception as e:	#万能异常
	print(e)except:			  	 #默认处理所有异常
	print("所有异常都可处理")print("继续运行...")

输出结果如下所示,会输出系统自带的提示错误:string index out of range,相对于解释器因为异常自己抛出来的一堆红色刺眼的字体,这种看起来舒服多了(能够“运筹帷幄”的异常才是好异常嘛哈哈哈)。另外这里用到“万能异常”Exception,基本所有没处理的异常都可以在此执行。最后一个except表示,如果没有指定异常,则默认处理所有的异常。

string index out of range继续运行...

3、try…except…finally…处理机制

  finally语句块表示,无论异常发生与否,finally中的语句都要执行完毕。也就是可以很霸气的说,无论产生的异常是被except捕获到处理了,还是没被捕获到解释器将错误输出来了,都统统要执行这个finally。还是原来简单的例子加上finally语句块如下,代码如下:

number = 'hello'try:	print(number[500])	#数组越界访问,抛出IndexError异常except IndexError:	print("下标越界啦!")finally:	print("finally!")print("继续运行...")		#运行

结果如下,数据越界访问异常被捕获到后,先执行except 语句块,完毕后接着执行了finally语句块。因为异常被执行,所以后面代码继续运行。

下标越界啦!finally!
继续运行...

  对try语句块进行修改,打印abc变量值,因为abc变量没定义,所以会出现不会被捕获的NameError异常信号,代码如下所示:

number = 'hello'try:	print(abc)	#变量未被定义,抛出NameError异常except IndexError:	print("下标越界啦!")finally:	print("finally!")print("继续运行...")	#不运行

结果如下,因为NameError异常信号没法被处理,所以解释器将程序中断,并将错误信息输出,但这过程中依然会执行finally语句块的内容。因为程序被迫中断了,所以后面代码不运行。

finally!	#异常没被捕获,也执行了finallyTraceback (most recent call last):
	File "E:/Test_code/test.py",line 3,in <module>
   		print("abc")NameError: name &#39;abc&#39; is not defined

  理解到这里,相信:try…finally…这种机制应该也不难理解了,因为省略了except 捕获异常机制,所以异常不可能被处理,解释器会将程序中断,并将错误信息输出,但finally语句块的内容依然会被执行。例子代码如下:

number = &#39;hello&#39;try:	print(abc)	#变量未被定义,抛出NameError异常finally:	print("finally!")print("继续运行...")

运行结果:

finally!	#异常没被捕获,也执行了finallyTraceback (most recent call last):
	File "E:/Test_code/test.py",line 3,in <module>
   		print("abc")NameError: name &#39;abc&#39; is not defined

4、assert断言处理机制

  assert语句先判断assert后面紧跟的语句是True还是False,如果是True则继续往下执行语句,如果是False则中断程序,将错误信息输出。

assert 1 == 1 	#为True正常运行assert 1 == 2	#为False,终止程序,错误信息输出

5、with…as处理机制

  with…as一般常用在文件处理上,我们平时在使用类似文件的流对象时,使用完毕后要调用close方法关闭,很麻烦,这里with…as语句提供了一个非常方便且人性的替代方法,即使突发情况也能正常关闭文件。举个例子代码如下,open打开文件后将返回的文件流对象赋值给fd,然后在with语句块中使用。

with open(&#39;e:/test.txt&#39;,&#39;r&#39;) as fd:
	fd.read()
	print(abc)	#变量未被定义,程序终止,错误信息输出print("继续运行...")

  正常情况下,这里的with语句块完毕之后,会自动关闭文件。但如果with语句执行中发生异常,如代码中的变量未定义异常,则会采用默认异常处理机制,程序终止,错误信息输出,后面代码不被运行,文件也会正常关闭。

三、python异常自定义

  说了这么多异常的使用,终于可以回到我前言所说的在实际项目中存在的问题,即错误码的返回和数值的返回是冲突的(因为错误码也是数值),这时候便可以用异常的抛出和捕获来完成错误码的传递,即try和except 。但系统发生异常时抛出的是系统本身定义好的异常类型,跟自己的错误码又有何关系?这就是我接下来要说的内容:如何定义自己的异常并且能够被except 所捕获

1、异常自定义

  实际开发中,有时候系统提供的异常类型往往都不能满足开发的需求。这时候就要使用到异常的自定义啦,你可以通过创建一个新的异常类来拥有自己的异常。自己定义的异常类继承自 Exception 类,可以直接继承,或者间接继承。栗子举起来:

class MyException(Exception):
    &#39;&#39;&#39;自定义的异常类&#39;&#39;&#39;
    def __init__(self, error_num):	#异常类对象的初始化属性
        self.error_num = error_num    def __str__(self):				#返回异常类对象说明信息
        err_info = [&#39;超时错误&#39;,&#39;接收错误&#39;]
        return err_info[self.error_num]

  该类继承自Exception 类,并且新类的名字为MyException,这跟前面我们一直在用的IndexError这个异常类一样,都是继承自Exception 类。__init__为构造函数,当我们创建对象时便会自动调用,__str__为对象说明信息函数,当使用print输出对象的时候,只要自己定义了__str__方法,那么就会打印从在这个方法中return的数据。
  即print(MyException(0))时,便可打印“超时错误”这个字符串,print(MyException(1))时,便可打印“接收错误”这个字符串,心细的你应该可以理解,MyException(x)为临时对象(x是传入错误码参数,这里只定义了0和1),与a = MyException(x),a为对象一个样子 。 这里有一个好玩的说法,在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法。

2、异常抛出raise

  现在我们自己定义的错误定义好了(上面的MyException),怎么能像IndexError一样让except捕获到呢?于是乎raise关键字派上用场。我们在异常机制中用try…except时,一般都是将可能产生的错误代码放到try语句块中,这时出现异常则系统便会自动将其抛出,比如IndexError,这样except就能捕获到,所以我们只要将自定义的异常在需要的时候将其抛出即可。
  raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类),那么我们刚刚定义的异常类就可以用啦,举个简单例子:

try:
    raise MyException(0)	# 自己定义的错误类,将错误码为0的错误抛出except MyException as e:
    print(e) 	  			# 输出的是__str__返回的内容,即“超时错误”

  这里我直接将自己定义的错误抛出,…as e就是把得到的错误当成对象e,这样才可以访问其属性和方法。因为自己定义的错误中可以支持多个错误码(本质还是MyException这个错误),所以便可实现传入不同错误码就可打印不同错误信息。

3、异常捕获

  只要我们在try中将错误raise出来,except就可以捕获到(当然,异常必须是Exception 子类才能被捕获),将前面两个例子整合起来,代码如下:

&#39;&#39;&#39;错误码:0代表超时错误,1代表接收错误&#39;&#39;&#39;class MyException(Exception):
    &#39;&#39;&#39;自定义的异常类&#39;&#39;&#39;
    def __init__(self, error_num):	# 异常类对象的初始化属性
        self.error_num= error_num    def __str__(self):				# 返回异常类对象指定错误码的信息
        err_info = [&#39;超时错误&#39;,&#39;接收错误&#39;]
        return err_info[self.error_num]def fun()
	raise MyException(1) 			# 抛出异常对象,传入错误码1def demo_main():
    try:
        fun()
    except MyException as ex:		# 这里要使用MyException进行捕获,对象为ex
        print(ex) 	   				# 输出的是__str__部分返回的内容,即“接收错误”
        print(ex.error_num) 		# 输出的是__init__中定义的error_num,即1demo_main()							#此处开始运行

  代码从demo_main函数开始执行,进入try语句块,语句块中的fun()函数模拟代码运行失败时raise 自定义的异常,except 正常接收后通过as 关键字得到异常对象,访问该异常对象,便可正常输出自定义的异常信息和自定义的错误码。

四、异常使用注意事项

此注意事项参考博文:异常机制使用细则.

1、不要太依赖异常机制

  python 的异常机制非常方便,对于信息的传递中十分好用(这里信息的传递主要有三种,参数传递,全局变量传递,以及异常机制传递),但滥用异常机制也会带来一些负面影响。过度使用异常主要表现在两个方面:①把异常和普通错误混淆在一起,不再编写任何错误处理代码,而是以简单地引发异常来代苦所有的错误处理。②使用异常处理来代替流程控制。例子如下:

buf = "hello"#例1:使用异常处理来遍历arr数组的每个元素try:
    i = 0    
    while True:
        print (buf [i])
        i += 1except:
    pass#例2:使用流程控制避免下标访问异常i = 0while i < len(buf ):
    print(buf [i])
    i += 1

  例1中假如循环过度便会下标访问异常,这时候把错误抛出,再进行一系列处理,显然是不可取的,因为异常机制的效率比正常的流程控制效率差,显然例2中简单的业务流程就可以避开这种错误。所以不要熟悉了异常的使用方法后,遇到这种简单逻辑,便不管三七二十一引发异常后再进行解决。对于完全己知的错误和普通的错误,应该编写处理这种错误的代码,增加程序的健壮性。只有对于外部的、不能确定和预知的运行时错误才使用异常

2、不要在 try 块中引入太多的代码

大量のコードを try ブロックに配置することは「単純」に見え、コードのフレームワークは理解しやすいですが、try ブロックのコードが大きすぎてビジネスが複雑すぎるため、 はtry ブロックにコードが出現するため、異常の可能性が大幅に高まり、異常の原因を分析することがさらに困難になります。
- ブロックが大きすぎる場合、異なる例外に対して異なる処理ロジックを提供するために、try ブロックの後に多数の例外ブロックを続けることは避けられません。同じ try ブロックの後に多数のブロックが続く場合は、それらの間の論理関係を分析する必要があり、プログラミングが複雑になります。したがって、大きな try ブロックを複数の小さなブロックに分割し、それぞれ例外をキャプチャして処理できます。

#3. キャッチした例外を無視しないでください

例外を無視しないでください。例外が捕捉されたので、

excel ブロッ​​クは何らかの有用な処理を行い、例外を処理して修正する必要があります。ブロック全体を空のままにしたり、単純な例外情報を出力するだけの場合は不適切です。具体的な処理方法は次のとおりです。 例外を処理します。
例外を適切に修復し、例外が発生した場所をバイパスして実行を継続するか、期待されるメソッドの戻り値の代わりに他のデータを使用して計算を実行するか、ユーザーに再操作を促します。プログラムは可能な限り例外を修復し、プログラムが動作を再開できるようにする必要があります。 新しい例外を再発生させます。
現在の実行環境でできることをできる限りすべて実行してから、例外を変換し、例外を現在の層の例外にパッケージ化して、上位層の呼び出し元に再度渡します。
適切なレイヤーで例外を処理します
。現在の層が例外を処理する方法を知らない場合は、例外をキャッチするために現在の層でExcept ステートメントを使用せず、上位層の呼び出し元に例外の処理を任せてください。

概要

この記事では、システムのデフォルトの例外から始まり、例外とは何かを説明し、システム内の一般的な例外クラスを要約してから、例外をカスタマイズする方法について説明します。例外の定義からスロー、カスタム例外の定義の取得と使い方まで、最後にPythonの例外を使用する際の注意点をまとめます。

関連する無料学習の推奨事項:

Python チュートリアル(ビデオ)

すべての数値計算エラーの基本クラス
浮動小数点計算エラー
数値演算が最大制限を超えています
除算 (またはモジュロ) ) ゼロ (すべてのデータ型)
Assertion ステートメントが失敗しました
#NameError
UnboundLocalError
ReferenceError
RuntimeError
NotImplementedError
構文エラー Python
IndentationError
TabError タブ
##TypeError タイプに対する無効な操作
#エンコード中のエラー
変換中のエラー
警告の基本クラス
Warning非推奨の機能について
将来のセマンティクスの構築について警告が変更されます
long への自動昇格に関する古い警告
非推奨になる機能に関する警告
疑わしい実行時の動作に関する警告
疑わしい構文の警告
によって生成された警告ユーザーコード

以上がPythonの例外メカニズムを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。