Python “如何沉默”;sys.EXPEPTHOOK缺失“1;错误?
注意:我没有尝试在Windows下或在2.7.3以外的Python版本中重现下面描述的问题 引出问题的最可靠方法是通过管道将以下测试脚本的输出传输到Python “如何沉默”;sys.EXPEPTHOOK缺失“1;错误?,python,exception,io,Python,Exception,Io,注意:我没有尝试在Windows下或在2.7.3以外的Python版本中重现下面描述的问题 引出问题的最可靠方法是通过管道将以下测试脚本的输出传输到:(在bash下): 即: 我的问题是: 当脚本如图所示运行时(在Unix/bash下),如何修改上面的测试脚本以避免出现错误消息 (如测试脚本所示,除了,不能使用尝试捕获错误) 诚然,上面的例子是高度人工的,但当我的脚本输出通过第三方软件传输时,我有时会遇到同样的问题 错误消息当然是无害的,但它会让最终用户感到不安,所以我想让它安静下来 编辑:以下
:
(在bash
下):
即:
我的问题是:
当脚本如图所示运行时(在Unix/bash
下),如何修改上面的测试脚本以避免出现错误消息
(如测试脚本所示,除了,不能使用尝试捕获错误)
诚然,上面的例子是高度人工的,但当我的脚本输出通过第三方软件传输时,我有时会遇到同样的问题
错误消息当然是无害的,但它会让最终用户感到不安,所以我想让它安静下来
编辑:以下脚本与上面的原始脚本不同,只是它重新定义了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
在您的程序中,抛出一个无法使用try/except块捕获的异常。要抓住他,重写函数sys.excepthook
:
import sys
sys.excepthook = lambda *args: None
发件人:
sys.excepthook(类型、值、回溯)
当引发异常并取消捕获时,解释器调用
带有三个参数的sys.excepthook,异常类,异常
实例和一个回溯对象。在本周的互动会议中
在控件返回到提示符之前发生;在Python中
程序这发生在程序退出之前。处理
这样的顶级异常可以通过分配另一个异常来定制
sys.excepthook的三参数函数
示例:
import sys
import logging
def log_uncaught_exceptions(exception_type, exception, tb):
logging.critical(''.join(traceback.format_tb(tb)))
logging.critical('{0}: {1}'.format(exception_type, exception))
sys.excepthook = log_uncaught_exceptions
当脚本如图所示运行时(在Unix/bash
下),如何修改上面的测试脚本以避免出现错误消息
您需要防止脚本将任何内容写入标准输出。这意味着删除任何print
语句和对sys.stdout.write
的任何使用,以及调用这些语句的任何代码
发生这种情况的原因是,您正在将Python脚本的非零量输出传输到从未从标准输入读取的内容。这不是:
命令所独有的;通过管道传输到任何不读取标准输入的命令,可以获得相同的结果,例如
python testscript.py | cd .
或者对于一个更简单的例子,考虑一个脚本<代码>打印机.Py < /> > >包含
print 'abcde'
然后
将产生相同的错误
当您将一个程序的输出通过管道传输到另一个程序时,写入程序生成的输出将备份到缓冲区中,并等待读取程序从缓冲区请求数据。只要缓冲区是非空的,任何试图关闭写入文件对象的尝试都会失败并出现错误。这是您看到的消息的根本原因
触发错误的特定代码在Python的C语言实现中,这解释了为什么不能用try
/捕捉错误,除了
块:它在脚本内容完成处理后运行。基本上,当Python关闭自身时,它会尝试关闭stdout,但是失败了,因为仍然有缓冲输出等待读取。因此Python会像往常一样尝试报告此错误,但作为终结过程的一部分,sys.excepthook
已经被删除,因此失败。Python然后尝试将一条消息打印到sys.stderr,但该消息已经被释放,所以再次失败。您在屏幕上看到这些消息的原因是Python代码确实包含一个应急fprintf
,用于直接向文件指针写入一些输出,即使Python的输出对象不存在
技术细节
对于感兴趣的这个过程的细节,让我们看看Python解释器的停机顺序,它是在<代码> python Run.c<代码> >
中实现的。stdout
和stderr
sys
模块保存标准流对象的最后剩余引用,因此当\u PyModule\u Clear
取消设置这些引用时,它们就可以被释放。1fileobject.c
中完成的。首先使用恰当命名的:
对于标准文件对象,关闭文件(f)
,如果仍有数据要写入文件指针,则会设置错误条件<代码>文件\u dealoc然后检查错误情况并打印您看到的第一条消息:
if (!ret) {
PySys_WriteStderr("close failed in file object destructor:\n");
PyErr_Print();
}
else {
Py_DECREF(ret);
}
PyErr_PrintEx
尝试从sys.excepthook
访问Python异常打印机
hook = PySys_GetObject("excepthook");
如果在Python程序的正常过程中执行此操作,则没有问题,但在这种情况下,sys.excepthook
已被清除。2 Python检查此错误情况并将第二条消息打印为通知
if (hook && hook != Py_None) {
...
} else {
PySys_WriteStderr("sys.excepthook is missing\n");
PyErr_Display(exception, v, tb);
}
excepthook
之后,Python会返回到使用打印异常信息,这是显示异常的默认方法
ret = close_the_file(f);
if (!ret) {
PySys_WriteStderr("close failed in file object destructor:\n");
PyErr_Print();
}
else {
Py_DECREF(ret);
}
hook = PySys_GetObject("excepthook");
if (hook && hook != Py_None) {
...
} else {
PySys_WriteStderr("sys.excepthook is missing\n");
PyErr_Display(exception, v, tb);
}
PyObject *f = PySys_GetObject("stderr");
if (f == NULL || f == Py_None)
fprintf(stderr, "lost sys.stderr\n");
python printer.py | python printer.py
--- a/testscript.py
+++ b/testscript.py
@@ -9,5 +9,6 @@ sys.excepthook = excepthook
try:
for n in range(20):
print n
+ sys.stdout.flush()
except:
pass
$ python testscript.py | :
$
print "Good Bye"
print ("Good Bye")