5

書くすべての関数を常に try...except ブロックで囲む必要がありますか? これを尋ねるのは、ある関数で を発生さExceptionせ、この関数を呼び出す呼び出し元に例外がない場合があるためです。

def caller():
   stdout, stderr = callee(....)


def callee():
   ....
    if stderr:
       raise StandardError(....)

その後、アプリケーションがクラッシュします。この明らかなケースでは、callee と caller を で囲みたいと思いますtry..except

しかし、私は非常に多くの Python コードを読んできましたが、常にこれらを実行しているわけではありませんtry..block


def cmd(cmdl):
    try:
        pid = Popen(cmdl, stdout=PIPE, stderr=PIPE)
    except Exception, e:
        raise e
    stdout, stderr = pid.communicate()
    if pid.returncode != 0:
        raise StandardError(stderr)
    return (stdout, stderr)

def addandremove(*args,**kwargs):
    target = kwargs.get('local', os.getcwd())
    f = kwargs.get('file', None)
    vcs = kwargs.get('vcs', 'hg')

    if vcs is "hg":
        try:
            stdout, stderr = cmd(['hg', 'addremove', '--similarity 95'])
        except StandardError, e:
            // do some recovery
        except Exception, e:
            // do something meaningful
    return True

私を悩ませている本当のことはこれです:

ステートメントの 1 つで呼び出す 3 番目の関数がある場合、その呼び出しaddandremove()も try..except ブロックで囲みますか? この 3 番目の関数に 3 つの行があり、各関数呼び出し自体に try-except がある場合はどうなるでしょうか? 立ててすみません。しかし、これは私が得られない種類の問題です。

4

6 に答える 6

11

例外は、名前が示すように、例外的な状況 (実際には発生してはならないこと) のためのものです。

..そして、それらはおそらく発生すべきではないため、ほとんどの場合、それらを無視できます。これは良いことです。

特定の例外を除いて行う場合があります。たとえば、私が行う場合:

urllib2.urlopen("http://example.com")

この場合、「サーバーに接続できません」というエラーが発生することが予想されるので、次のようにします。

try:
    urllib2.urlopen("http://example.com")
except urllib2.URLError:
    # code to handle the error, maybe retry the server,
    # report the error in a helpful way to the user etc

ただし、考えられるすべてのエラーをキャッチしようとしても無駄です。問題が発生する可能性のあるものは数え切れないほどあります。奇妙な例として、モジュールが属性を変更して削除した場合はどうなるでしょうかurllib2。そのようなエラーを処理できる正気の方法はないため、例外を伝播させるだけですurlopenNameError

トレースバックでコードを終了させることは良いことです。これにより、問題の発生場所とその原因 (例外とそのメッセージに基づいて) を簡単に確認し、問題の原因を修正したり、例外を処理したりできます。正しい位置...

要するに、何か役に立つことができる場合にのみ、例外を処理してください。そうでない場合、考えられる無数のエラーをすべて処理しようとすると、コードのバグが増え、修正が難しくなるだけです。


あなたが提供する例では、try/except ブロックは何もしません。例外を再発生させるだけなので、より整然としたものと同じです。

def cmd(cmdl):
    pid = Popen(cmdl, stdout=PIPE, stderr=PIPE)
    stdout, stderr = pid.communicate()
    if pid.returncode != 0:
        raise StandardError(stderr)
    return (stdout, stderr)

# Note: Better to use actual args instead of * and **,
# gives better error handling and docs from help()
def addandremove(fname, local = None, vcs = 'hg'):
    if target is None:
       target = os.getcwd() 

    if vcs is "hg":
        stdout, stderr = cmd(['hg', 'addremove', '--similarity 95'])
    return True

私が期待する例外処理関連の唯一のことは、「hg」コマンドが見つからない場合の処理​​であり、結果の例外は特に説明的ではありません。したがって、ライブラリの場合、次のようにします。

class CommandNotFound(Exception): pass

def cmd(cmdl):
    try:
        pid = Popen(cmdl, stdout=PIPE, stderr=PIPE)
    except OSError, e:
        if e.errno == 2:
            raise CommandNotFound("The command %r could not be found" % cmdl)
        else:
            # Unexpected error-number in OSError,
            # so a bare "raise" statement will reraise the error
            raise

    stdout, stderr = pid.communicate()
    if pid.returncode != 0:
        raise StandardError(stderr)
    return (stdout, stderr)

これは、紛らわしい可能性のある「OSError」例外をより明確な「CommandNotFound」にラップするだけです。

質問を読み直すと、Python の例外がどのように機能するかについて誤解している可能性があると思われます (「この関数を呼び出す呼び出し元には例外がありません」ビットなので、うまくいけば明確になります:

呼び出し元関数は、子関数から発生する可能性のある例外についての知識を必要としません。関数を呼び出すだけで、正常にcmd()機能することを願っています。

あなたのコードがmystuffモジュールにあり、他の誰かがそれを使用したいとします。彼らはそうするかもしれません:

import mystuff

mystuff.addandremove("myfile.txt")

または、ユーザーがhgインストールしていない場合は、適切なエラー メッセージを表示して終了したい場合があります。

import mystuff

try:
    mystuff.addandremove("myfile.txt")
except mystuff.CommandNotFound:
    print "You don't appear to have the 'hg' command installed"
    print "You can install it with by... etc..."
    myprogram.quit("blahblahblah")
于 2012-07-13T21:52:15.250 に答える
6

try/except句は、発生したエラーの処理方法を知っている場合にのみ役立ちます。次のプログラムを実行します。

while True:
    n=raw_input("Input a number>")
    try:
       n=float(n)
       break
    except ValueError:
       print ("That wasn't a number!")  #Try again.

ただし、次のような関数がある場合があります。

def mult_2_numbers(x,y):
    return x*y

そして、ユーザーはそれを次のように使用しようとするかもしれません:

my_new_list=mult_2_numbers([7,3],[8,7])

ユーザーはこれを try/except ブロックに入れることができmy_new_listますが、その後は定義されず、後で例外 (おそらく NameError) が発生するだけです。その場合、トレースバックの行番号/情報が実際の問題ではないコードを指しているため、デバッグが難しくなります。

于 2012-07-13T21:22:36.220 に答える
6

例外のソースを明確に特定できるように、try catch ブロックを使用する必要があります。これらのブロックは好きなところに配置できますが、何らかの有用な情報が生成されない限り、追加する必要はありません。

于 2012-07-13T21:16:36.800 に答える
1

イントロスペクション タイプのツールと「例外」の処理に関して、コーディング チームが行うべきプログラミング上の決定事項がいくつかあります。

例外処理を使用するのに適した場所の 1 つは、ファイル操作などのオペレーティング システムの呼び出しです。理由としては、たとえば、ファイルへのアクセスがクライアント アプリケーションによるアクセスから制限されている可能性があります。このアクセス制限は通常、Python アプリケーション機能ではなく、OS 管理タスクです。したがって、例外は、アプリケーションが制御できない場合に適しています。

前の段落の例外の適用をより広く変更できます。つまり、チームのコードの制御外のものに例外を使用するという意味で、すべての「デバイス」または OS タイマー、シンボリック リンク、ネットワーク接続などの OS リソースなどに適用できます。など

もう 1 つの一般的なユース ケースは、多数の例外を処理するように設計されたライブラリまたはパッケージを使用する場合で、そのパッケージでは、その例外をキャッチまたはコーディングする必要があります。一部のパッケージは、できるだけ例外をスローしないように設計されており、戻り値に基づいてコーディングする必要があります。その後、例外はまれになるはずです。

一部のコーディング チームは、アプリケーション内の「イベント」のフリンジ ケースをログに記録する方法として例外を使用します。

例外を使用するかどうかを決定するとき、多くの try/except を使用せずに失敗を最小限に抑えるようにプログラミングし、呼び出しルーチンに有効な戻り値を期待させるか、無効な戻り値を期待させていることに気付きました。または私は失敗のためにプログラムします。つまり、多くの try/except ブロックを使用して、関数によって予想される失敗をプログラムします。TCP での作業のように、「予想される」障害に対するプログラミングを考えてみてください。パケットは、そこに到達すること、または順序どおりに到達することさえ保証されていませんが、送信/読み取りの再試行などを使用した TCP の例外処理があります。

個人的には、可能な限り最小のブロック サイズ (通常は 1 行のコード) で try-except ブロックを使用します。

于 2012-07-13T22:37:32.983 に答える
0

エラーの内容がわかっている場合は、デバッグ目的で try/except を使用します。それ以外の場合は、すべての関数に対して try/except を使用する必要はありません。

于 2012-07-13T21:32:55.993 に答える
0

それはあなた次第です; 主な例外の役割には以下が含まれます (この素晴らしい本からの引用):

  • エラー処理
  • イベント通知
  • 特例扱い
  • 終了アクション
  • 異常な制御フロー
于 2012-07-13T21:26:04.060 に答える