77

オンラインで読むプログラマーは、を使用しsys.exit、他のプログラマーはを使用しますSystemExit
基本的な質問でごめんなさい:

  1. 違いはなんですか?
  2. 関数内でSystemExitまたはsys.exitを使用する必要があるのはいつですか?

ref = osgeo.ogr.Open(reference)
if ref is None:
    raise SystemExit('Unable to open %s' % reference)

また

ref = osgeo.ogr.Open(reference)
if ref is None:
    print('Unable to open %s' % reference)
    sys.exit(-1)
4

7 に答える 7

41

実用的な違いはありませんが、サンプルコードには別の違いがあります。print標準出力になりますが、例外テキストは標準エラーになります(これはおそらくあなたが望むものです)。

于 2012-12-21T15:26:07.317 に答える
36

sys.exit(s)raise SystemExit(s)前者のdocstringで説明されているように、はの省略形です。試してみてくださいhelp(sys.exit)。したがって、サンプルプログラムのいずれかの代わりに、次のことができます。

sys.exit('Unable to open %s' % reference)
于 2012-12-21T15:23:09.293 に答える
24

を上げることに加えて、3つの出口機能がありますSystemExit

基になるものはですos._exit。これには1つのint引数が必要であり、クリーンアップなしですぐに終了します。これに触れたくなることはまずないでしょうが、そこにあります。

sys.exitはsysmodule.cで定義されており、実行するだけです。PyErr_SetObject(PyExc_SystemExit, exit_code);これは、を直接発生させるのと実質的に同じSystemExitです。詳細には、 and vs opcallsが必要なため、レイズSystemExitはおそらくより高速です。また、わずかに小さいバイトコード(4バイト少ない)を生成します( Noneを返すことが期待されるため、使用する場合は1バイト余分になります。したがって、余分なものが含まれます) 。 sys.exitLOAD_ATTRCALL_FUNCTIONRAISE_VARARGSraise SystemExitfrom sys import exitsys.exitPOP_TOP

最後の終了関数は、で定義され、REPLまたはREPLでsite.pyエイリアス化されます。これは実際にはクラスのインスタンスです(したがって、カスタムを持つことができるため、実行速度が最も遅い可能性があります。また、レイズする前に閉じるため、REPLでのみ使用することをお勧めします。 exitquitQuitter__repr__sys.stdinSystemExit

処理方法についてSystemExitは、最終的にVMがos._exitを呼び出すようになりますが、その前に、ある程度のクリーンアップが行われます。また、モジュールatexit._run_exitfuncs()を介して登録されたコールバックを実行する実行も実行されます。atexit直接呼び出すと、ステップos._exitがバイパスされます。atexit

于 2016-02-16T10:49:29.200 に答える
12

私の個人的な好みは、少なくともSystemExit上げられ(またはさらに良い-より意味があり、十分に文書化されたカスタム例外)、「メイン」関数に可能な限り近づけて、それを最後のチャンスと見なすことができることです。有効な終了かどうか。ライブラリ/深く埋め込まれた関数sys.exitは、設計の観点からは非常に厄介です。(一般的に、終了は可能な限り「高い」必要があります)

于 2012-12-21T15:25:55.100 に答える
5

ドキュメントによると、sys.exit(s)効果的raise SystemExit(s)にそうするので、それはほとんど同じことです。

于 2012-12-21T15:23:24.050 に答える
4

SystemExitは例外です。これは基本的に、プログラムが停止してエラーを発生させたいという動作をしたことを意味します。sys.exitプログラムを終了するために呼び出すことができる関数であり、システムにリターンコードを返す可能性があります。

編集:それらは確かに同じものなので、唯一の違いはプログラムの背後にあるロジックにあります。例外は、ある種の「望ましくない」動作です。関数の呼び出しが、プログラマーの観点からは、より「標準的な」アクションであるかどうかは関係ありません。

于 2012-12-21T15:23:46.237 に答える
3

違いは多くの回答によって答えられていますが、https://mail.python.org/pipermail/python-list/2016-April/707470.htmlは興味深い点を示しています。

TL; DR:「通常の」例外を発生させて、スクリプトのトップレベルでのみ使用SystemExitすることをお勧めします。sys.exit

私はPython2.7とLinuxを使用していますが、sys.exit(1)をraise SystemExitに置き換えることができれば、簡単なコードの提案が必要です。

==実際のコード==

def main():    
    try:
       create_logdir()
       create_dataset()
       unittest.main()    
     except Exception as e:
       logging.exception(e)
       sys.exit(EXIT_STATUS_ERROR)

if __name__ == '__main__':    main()

==変更されたコード==

def main():    
    try:
       create_logdir()
       create_dataset()
       unittest.main()    
    except Exception as e:
       logging.exception(e)
       raise SystemExit

if __name__ == '__main__':    
    main()

私は個人的にこれらの両方に反対しています。私の好みのパターンは次のようなものです。

  def main(argv):
    try:
      ...
    except Exception as e:
      logging.exception(e)
      return 1

  if __name__ == '__main__':
    sys.exit(main(sys.argv))

main()が、通常の戻り値を持つ通常の関数に戻っていることに注意してください。

また、私たちのほとんどは「例外を除いて」を避け、バブルアウトを除いてトップレベルにするだけです。そうすれば、デバッグ用のスタックバックトレースを取得できます。例外のログ記録を防ぎ、コンソール出力を醜くすることに同意しますが、それは勝利だと思います。そして、例外をログに記録したい場合は、常に次のようになります。

試してみてください:...例外をeとして除く:logging.exception(e)raise

例外をログに暗唱し、それでも通常どおりにバブルアウトさせます。

「例外例外」パターンの問題は、 理解している特定の例外の狭いセットだけでなく、すべての例外をキャッチして非表示にすることです。

最後に、裸のExceptionクラスを発生させることは嫌われています。Python 3では、実際には禁止されていると思うので、とにかく移植できません。ただし、Pythonでも、クラスではなく、Exceptionインスタンスを指定するのが最適です。

SystemExit(1)を上げる

  1. tryブロックのすべての関数で、raiseを使用して例外がバブルアウトされています

    create_logdir()の例は、関数定義です。

def create_logdir():

try:os.makedirs(LOG_DIR)OSError as e:sys.stderr.write("ログディレクトリの作成に失敗しました...終了!!!")raise print "log file:"+corrupt_logはTrueを返します

def main():try:create_logdir()例外を除くe:logging.exception(e)raise SystemExit

(a)create_logdir()が失敗した場合、以下のエラーが発生します。これで問題ありませんか、このコードを改善する必要がありますか。

ログディレクトリの作成に失敗しました...終了します!!!ERROR:root:[Errno 17]ファイルが存在します:'/ var / log / dummy'

トレースバック(最後の最後の呼び出し):ファイル "corrupt_test.py"、行245、メインcreate_logdir()ファイル "corrupt_test.py"、行53、create_logdir os.makedirs(LOG_DIR)ファイル "/ usr / local / lib / python2.7 / os.py "、157行目、makedirs OSError:[Errno 17]ファイルが存在します:'/ var / log / dummy'

私はバブルアウトアプローチを好みます。おそらく、あなたが行ったようにログまたは警告メッセージを使用します。例:

logging.exception( "create_logdir failed:makedirs(%r):%s"%(LOG_DIR、e))raise

(また、そのログメッセージがより多くのコンテキストを記録するわけではありません。コンテキストは問題をデバッグするときに非常に役立ちます。)

非常に小さなスクリプトの場合、sys.stderr.writeは問題ありませんが、一般に、一般的に有用であることが判明した関数は、再利用するためにライブラリに移行する可能性があります。stderrが常にメッセージの場所であるとは限らないことを考慮してください。代わりに、必要に応じてerror()、wanr()、またはexception()を使用してロギングモジュールを読み取ります。内部関数に出力を配線せずに、出力がそのように移動する場所を構成するためのより多くの範囲があります。

  1. SystemExitまたはsys.exit(1)の代わりに、を上げるだけでいいですか。これは私には間違っているように見えます

    def main():

    試してみてください:create_logdir()e logging.exception(e)raiseとしての例外を除く

これは私自身がすることです。

考えてみてください。例外は「処理」されましたか。つまり、予期されたために状況が処理されたのでしょうか。そうでない場合は、プログラムで理解できないことが発生したことをユーザーに知らせるために、例外をバブルアウトします。

最後に、最も外側のmain()関数以外の内部からSystemExitまたはsys.exit()を実行することは一般的に悪いことです。そして、私はそこでさえそれに抵抗します。main関数は、うまく記述されていれば、他の場所から便利に呼び出されることが多く、それによって効果的にライブラリ関数になります(再利用されています)。このような関数は、プログラムを一方的に中止するべきではありません。失礼ですね!代わりに、例外をバブルアウトさせます。おそらく、main()の呼び出し元はそれを予期し、処理できます。あなた自身(つまり「メイン」)が例外を処理するのに十分なコンテキストを知らなくても、中止して「発生」させないことで、発信者から適切なことを行う機会を奪いました。

だから私は自分自身を「育てる」ためです。そして、エラーをログに記録したいという理由だけで。例外をログに記録したくない場合は、try / exceptionを完全に回避し、 コードを単純化することができます。呼び出し元に未処理の例外について心配させてください。

于 2018-03-01T12:32:45.733 に答える