[解決済み] sys.excepthook is missing" エラーの対処方法について教えてください。
質問内容
注意:WindowsやPythonの2.7.3以外のバージョンで以下の問題を再現することは試していません。
この問題を引き起こす最も確実な方法は、以下のテストスクリプトの出力を、以下のようにパイプすることです。
:
(以下
bash
):
try:
for n in range(20):
print n
except:
pass
すなわち
% python testscript.py | :
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
質問です。
上記のテストスクリプトはどのように修正すればよいのでしょうか のようにスクリプトを実行すると、エラーメッセージを回避することができます(Unix/
bash
)?
(テストスクリプトが示すように、このエラーは
try-except
.)
上の例は非常に人工的なものですが、同じ問題にぶつかっています。 時々 私のスクリプトの出力がサードパーティのソフトウェアにパイプされているとき。
このエラーメッセージは確かに無害なのですが、エンドユーザーにとっては不愉快なものなので、黙らせたいのです。
EDIT: 以下のスクリプトは、上記のオリジナルスクリプトと異なり、sys.excepthookを再定義しているだけで、上記のものと全く同じ動作をします。
import sys
STDERR = sys.stderr
def excepthook(*args):
print >> STDERR, 'caught'
print >> STDERR, args
sys.excepthook = excepthook
try:
for n in range(20):
print n
except:
pass
解決方法は?
<ブロッククオート
上記のテストスクリプトをどのように修正すれば、スクリプトを以下のように実行したときにエラーメッセージが表示されないようにできますか(Unix/
bash
)?
スクリプトが標準出力に何も書き込まないようにする必要があります。つまり
print
ステートメントと
sys.stdout.write
また、それらを呼び出すすべてのコードも同様です。
この現象が起こる理由は、Pythonスクリプトから標準入力から決して読み込まないものに、ゼロでない量の出力をパイプで送っているからです。これは
:
標準入力を読まないコマンドにパイプしても同じ結果になります。
python testscript.py | cd .
また、もっと簡単な例として、スクリプトを考えてみましょう。
printer.py
を含むだけである。
print 'abcde'
次に
python printer.py | python printer.py
も同じエラーになります。
あるプログラムの出力を別のプログラムにパイプする場合、書き込みプログラムで生成された出力はバッファにバックアップされ、読み込みプログラムがそのデータをバッファから要求するのを待ちます。バッファが空でない限り、書き込み用ファイルオブジェクトを閉じようとすると、エラーで失敗するはずです。これが、あなたが見ているメッセージの根本的な原因です。
このエラーを引き起こす特定のコードは、PythonのC言語実装にあり、そのため、このエラーを
try
/
except
ブロック: スクリプトの内容の処理が終了した後に実行されます。基本的に、Pythonが自分自身をシャットダウンしている間、Pythonは以下のものを閉じようとします。
stdout
しかし、バッファリングされた出力がまだ読み込まれるのを待っているため、これは失敗です。そこで Python はこのエラーを通常と同じように報告しようとしますが
sys.excepthook
はすでにファイナライズ処理の一部として削除されているので、これは失敗です。Pythonは次にメッセージを
sys.stderr
しかし、これはすでに解放されているので、またもや失敗です。画面にメッセージが表示されるのは、Pythonのコードに不測の事態が含まれているためです。
fprintf
の出力オブジェクトが存在しない場合でも、ファイルポインタに直接出力を書き出すことができます。
技術的な詳細
この手順の詳細に興味がある方のために、Pythonインタープリタのシャットダウン・シーケンスを実装している
Py_Finalize
機能
の
pythonrun.c
.
-
終了フックを呼び出し、スレッドをシャットダウンした後、ファイナライズコードは
PyImport_Cleanup
を使用して、インポートされたすべてのモジュールをファイナライズし、デアロケートします。この関数が実行する最後のタスクは を削除します。sys
モジュール を呼び出すことで、主に構成されています。_PyModule_Clear
のような標準的なストリームオブジェクト (Python オブジェクト) を含む、モジュールの辞書のすべてのエントリをクリアするために使用します。stdout
そしてstderr
. -
ある値が辞書から削除されたり、新しい値に置き換えられたりしたとき。
その参照カウントはデクリメントされます。
を使って
その
Py_DECREF
マクロ . 参照カウントがゼロになったオブジェクトは、割り当て解除の対象となります。このためsys
モジュールは標準ストリームオブジェクトへの最後の参照を保持します。_PyModule_Clear
を使用することで、割り当てを解除することができます。 1 -
Pythonのファイルオブジェクトのデアロケーションは、以下の方法で行います。 その
file_dealloc
機能 でfileobject.c
. この最初の は、Pythonファイルオブジェクトのclose
メソッド を使用して、適切な名前のclose_the_file
機能 :ret = close_the_file(f);
標準的なファイルオブジェクトの場合。
close_the_file(f)
に委ね、Cfclose
機能 ファイルポインタに書き込むべきデータがまだある場合は、エラー条件を設定します。file_dealloc
は、そのエラー状態をチェックし、最初に表示されるメッセージを表示します。if (!ret) { PySys_WriteStderr("close failed in file object destructor:\n"); PyErr_Print(); } else { Py_DECREF(ret); }
-
このメッセージを表示した後、Pythonは例外を表示するために
PyErr_Print
. に委譲されます。PyErr_PrintEx
であり、その機能の一部としてPyErr_PrintEx
からPythonの例外プリンタにアクセスしようとします。sys.excepthook
.hook = PySys_GetObject("excepthook");
通常のPythonのプログラムで行うのであれば問題ないのですが、このような場合。
sys.excepthook
はすでにクリアされています。 2 Pythonはこのエラー状態をチェックし、通知として2番目のメッセージを表示します。if (hook && hook != Py_None) { ... } else { PySys_WriteStderr("sys.excepthook is missing\n"); PyErr_Display(exception, v, tb); }
-
欠品のご連絡をいただいた後
excepthook
Pythonは例外情報を表示するためにPyErr_Display
これはスタックトレースを表示するためのデフォルトの方法です。この関数が最初に行うことは、スタックトレースを表示するためにsys.stderr
.PyObject *f = PySys_GetObject("stderr");
この場合、それはうまくいきません。
sys.stderr
はすでにクリアされており、アクセスできない状態になっています。 3 そこで、このコードではfprintf
を直接送信して、3つ目のメッセージをCの標準エラーストリームに送信しています。if (f == NULL || f == Py_None) fprintf(stderr, "lost sys.stderr\n");
興味深いことに、Python 3.4+ では動作が少し変わっています。 標準出力とエラーストリームを明示的にフラッシュします。 組み込みモジュールがクリアされる前に。この方法では、書き込み待ちのデータがある場合、通常のファイナライズ手順で "偶発的" 失敗するのではなく、その状態を明示的に知らせるエラーが表示されるのです。また、もし
python printer.py | python printer.py
をPython 3.4で使用した場合、(括弧を付けてから)
print
ステートメントを使用すると、まったくエラーが発生しません。2回目のPythonの起動で何らかの理由で標準入力を消費しているのだろうが、それは全く別の問題である。
1
実は、それは嘘です。Pythonのimportの仕組みは
は、インポートされた各モジュールの辞書のコピーをキャッシュします。
になるまで解放されません。
_PyImport_Fini
が実行されます。
の実装の後半で
Py_Finalize
および
それは
標準ストリームオブジェクトへの最後の参照が消えたとき。参照カウントがゼロになると
Py_DECREF
オブジェクトを解放します。
すぐに
. しかし、本題の答えとして重要なのは、参照が
sys
モジュールのディクショナリが解放されます。
2
ここでも
sys
モジュールの辞書は、属性キャッシュ機構のおかげで、実際に何かが割り当て解除される前に完全にクリアされます。Pythonを
-vv
オプションを使用すると、ファイルポインタを閉じるというエラーメッセージが表示される前に、モジュールのすべての属性がアンセットされるのを確認することができます。
3 この特定の動作の部分だけは、前の脚注で述べた属性キャッシュの仕組みについて知っていなければ意味がないものです。
関連
-
[解決済み】socket.error: [Errno 48] アドレスはすでに使用中です。
-
[解決済み】インポートエラー。モジュール名 urllib2 がない
-
[解決済み] プログラムの実行やシステムコマンドの呼び出しはどのように行うのですか?
-
[解決済み] リストのリストからフラットなリストを作るには?
-
[解決済み] JavaでInputStreamを読み込んでStringに変換するにはどうすればよいですか?
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] 辞書を値で並べ替えるにはどうしたらいいですか?
-
[解決済み] リストが空かどうかを確認するにはどうすればよいですか?
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】2つの辞書を1つの式でマージする(辞書の和をとる)には?)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Pythonショートビデオクローラーチュートリアル
-
PythonによるExcelファイルの一括操作の説明
-
Python Pillow Image.save jpg画像圧縮問題
-
[解決済み】DataFrameのコンストラクタが正しく呼び出されない!エラー
-
[解決済み】socket.error: [Errno 48] アドレスはすでに使用中です。
-
[解決済み】Django: ImproperlyConfigured: SECRET_KEY 設定は空であってはならない
-
[解決済み】"No JSON object could be decoded "よりも良いエラーメッセージを表示する。
-
[解決済み】インポートエラー。モジュール名 urllib2 がない
-
[解決済み】ImportError: bs4という名前のモジュールがない(BeautifulSoup)
-
[解決済み】cアンダースコア式`c_`は、具体的に何をするのですか?