在Python 3中禁止打印输出"Exception ... ignored"消息

sda*_*aau 11 python bash python-2.7 python-3.x

Python中存在一个已知问题,当stdout上发生"Broken pipe"时,"文件对象析构函数中的关闭失败" - Python跟踪器问题11380 ; 在python中也可以看到- 为什么我的Python3脚本无法将其输出连接到head或tail(sys模块)?- Stack Overflow.

我想要做的是,在Python 2.7和Python 3+中打印出同样的自定义消息.所以我准备了一个测试脚本testprint.py并运行它(显示在bashUbuntu 11.04 中完成的片段):

$ cat > testprint.py <<"EOF"
import sys

def main():
  teststr = "Hello " * 5
  sys.stdout.write(teststr + "\n")

if __name__ == "__main__":
  main()
EOF

$ python2.7 testprint.py 
Hello Hello Hello Hello Hello 

$ python2.7 testprint.py | echo

close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr

$ python3.2 testprint.py | echo

Exception IOError: (32, 'Broken pipe') in <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> ignored
Run Code Online (Sandbox Code Playgroud)

正如以上链接所预期的那样,有两种不同的消息.在帮助管道错误(velocityreviews.com)中,建议使用sys.stdout.flush()强制Python 2注册IOError而不是该消息; 有了它,我们有:

$ cat > testprint.py <<"EOF"
import sys

def main():
  teststr = "Hello " * 5
  sys.stdout.write(teststr + "\n")
  sys.stdout.flush()

if __name__ == "__main__":
  main()
EOF

$ python2.7 testprint.py | echo

Traceback (most recent call last):
  File "testprint.py", line 9, in <module>
    main()
  File "testprint.py", line 6, in main
    sys.stdout.flush()
IOError: [Errno 32] Broken pipe

$ python3.2 testprint.py | echo

Traceback (most recent call last):
  File "testprint.py", line 9, in <module>
    main()
  File "testprint.py", line 6, in main
    sys.stdout.flush()
IOError: [Errno 32] Broken pipe
Exception IOError: (32, 'Broken pipe') in <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> ignored
Run Code Online (Sandbox Code Playgroud)

OK,越来越近......现在,顺便给"忽略"这些例外(或者对于我来说,有一个自定义错误消息替换),是来处理它们:

忽略异常 - comp.lang.python

>有没有办法让[解释器]忽略异常.
不.处理异常或编写不生成异常的代码.

...作为Python简介 - 处理异常说明,这样做的方法是try/except块.所以让我们试试:

$ cat > testprint.py <<"EOF"
import sys

def main():
  teststr = "Hello " * 5
  try:
    sys.stdout.write(teststr + "\n")
    sys.stdout.flush()
  except IOError:
    sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n")

if __name__ == "__main__":
  main()
EOF

$ python2.7 testprint.py | echo

Exc: <type 'exceptions.IOError'>

$ python3.2 testprint.py | echo

Exc: <class 'IOError'>
Exception IOError: (32, 'Broken pipe') in <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> ignored
Run Code Online (Sandbox Code Playgroud)

好的,所以尝试/除了我希望它用于Python 2.7 - 然后,Python 3.2都按预期处理,并仍然生成一个Exception ... ignored消息!有什么问题 - except IOError对于Python 3 来说还不够" "?但它必须 - 否则它不会打印自定义" Exc:..."消息!

那么 - 这里的问题是什么,为什么Exception ... ignored仍然在Python 3中打印,即使我正在处理异常?更重要的是,如何处理它,因此Exception ... ignored 不会得到了印?

sda*_*aau 4

关于此问题还有一些注意事项 - 问题仍未解决......首先:

\n\n

问题 6294:改进关闭异常忽略消息 - Python 跟踪器

\n\n
\n

此错误消息是在 PyErr_WriteUnraisable 中生成的,它是从许多上下文中调用的,包括 __del__ 方法。在关闭期间调用的 __del__ 方法很可能是生成您所说的错误的原因,但据我所知, __del__ 方法无法知道它是在关闭期间被调用的。因此,建议的对该消息的修复将不起作用。[....]
\n 但是,因为这是一条消息,您甚至无法捕获它\n 更改它应该是完全安全的。

\n
\n\n

嗯,谢谢你的这个消息,你不能陷入困境,非常方便。我相信这在某种程度上与del ()中忽略打印到 stderr 的异常有关- Stack Overflow,尽管该帖子(显然)讨论了自定义__del__方法。

\n\n

使用以下一些资源:

\n\n\n\n

...我修改了脚本,因此我重载了所有可能的处理程序,以查看是否有空间可以“处理”此异常,因此它不会被“忽略”:

\n\n
import sys\nimport atexit\nimport signal\nimport inspect, pprint\n\ndef signalPIPE_handler(signal, frame):\n    sys.stderr.write(\'signalPIPE_handler!\'+str(sys.exc_info())+\'\\n\')\n    return #sys.exit(0) # just return doesn\'t exit!\nsignal.signal(signal.SIGPIPE, signalPIPE_handler)\n\n_old_excepthook = sys.excepthook\ndef myexcepthook(exctype, value, intraceback):\n  import sys\n  import traceback\n  sys.stderr.write("myexcepthook\\n")\n  if exctype == IOError:\n    sys.stderr.write(" IOError intraceback:\\n")\n    traceback.print_tb(intraceback)\n  else:\n    _old_excepthook(exctype, value, intraceback)\nsys.excepthook = myexcepthook\n\ndef _trace(frame, event, arg):\n  if event == \'exception\':\n    while frame is not None:\n      filename, lineno = frame.f_code.co_filename, frame.f_lineno\n      sys.stderr.write("_trace exc frame: " + filename \\\n        + " " + str(lineno) + " " + str(frame.f_trace) + str(arg) + "\\n")\n      if arg[0] == IOError:\n        myexcepthook(arg[0], arg[1], arg[2])\n      frame = frame.f_back\n  return _trace\nsys.settrace(_trace)\n\ndef exiter():\n  import sys\n  sys.stderr.write("Exiting\\n")\natexit.register(exiter)\n\ndef main():\n  teststr = "Hello " * 5\n  try:\n    sys.stdout.write(teststr + "\\n")\n    sys.stdout.flush()\n  except IOError:\n    sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\\n")\n    #sys.exit(0)\n\n\nif __name__ == "__main__":\n  main()\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意此脚本运行方式的差异:

\n\n
$ python2.7 testprint.py | echo\n\nsignalPIPE_handler!(None, None, None)\n_trace exc frame: testprint.py 44 <function _trace at 0xb748e5dc>(<type \'exceptions.IOError\'>, (32, \'Broken pipe\'), <traceback object at 0xb748acac>)\nmyexcepthook\n IOError intraceback:\n  File "testprint.py", line 44, in main\n    sys.stdout.flush()\n_trace exc frame: testprint.py 51 None(<type \'exceptions.IOError\'>, (32, \'Broken pipe\'), <traceback object at 0xb748acac>)\nmyexcepthook\n IOError intraceback:\n  File "testprint.py", line 44, in main\n    sys.stdout.flush()\nExc: <type \'exceptions.IOError\'>\nExiting\n\n$ python3.2 testprint.py | echo\n\nsignalPIPE_handler!(None, None, None)\n_trace exc frame: testprint.py 44 <function _trace at 0xb74247ac>(<class \'IOError\'>, (32, \'Broken pipe\'), <traceback object at 0xb747393c>)\nmyexcepthook\n IOError intraceback:\n  File "testprint.py", line 44, in main\n    sys.stdout.flush()\n_trace exc frame: testprint.py 51 None(<class \'IOError\'>, (32, \'Broken pipe\'), <traceback object at 0xb747393c>)\nmyexcepthook\n IOError intraceback:\n  File "testprint.py", line 44, in main\n    sys.stdout.flush()\nExc: <class \'IOError\'>\nsignalPIPE_handler!(None, None, None)\nExiting\nsignalPIPE_handler!(None, None, None)\nException IOError: (32, \'Broken pipe\') in <_io.TextIOWrapper name=\'<stdout>\' mode=\'w\' encoding=\'UTF-8\'> ignored\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,signalPIPE_handler在 Python 3 中运行次数是原来的两倍!我想,如果Python中有某种“异常队列”,我可以“偷看”它,并删除其中的剩余事件signalPIPE_handler,从而抑制Exception ... ignored消息......但我不知道有任何这样的事物。

\n\n

最后,当尝试使用以下资源进行调试时,这些资源非常有用gdb

\n\n\n\n

...因为我没有python3-dbg,所以所有这些都简化为逐步执行机器指令(layout asm在 中gdb,然后按 Ctrl-X + A),这并没有真正告诉我太多信息。但以下是如何触发该问题gdb

\n\n

在一个终端中:

\n\n
$ mkfifo foo \n$ gdb python3.2\n...\nReading symbols from /usr/bin/python3.2...(no debugging symbols found)...done.\n(gdb) run testprint.py > foo\nStarting program: /usr/bin/python3.2 testprint.py > foo\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里它会阻塞;在同一目录的另一个终端中执行以下操作:

\n\n
$ echo <foo\n
Run Code Online (Sandbox Code Playgroud)\n\n

...然后返回到第一个终端 - 您应该看到:

\n\n
...\nStarting program: /usr/bin/python3.2 testprint.py > foo\n[Thread debugging using libthread_db enabled]\nUsing host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".\n\nProgram received signal SIGPIPE, Broken pipe.\n0x0012e416 in __kernel_vsyscall ()\n(gdb) bt\n#0  0x0012e416 in __kernel_vsyscall ()\n#1  0x0013c483 in __write_nocancel () from /lib/i386-linux-gnu/libpthread.so.0\n#2  0x0815b549 in ?? ()\n#3  0x08170507 in ?? ()\n#4  0x08175e43 in PyObject_CallMethodObjArgs ()\n#5  0x0815df21 in ?? ()\n#6  0x0815f94e in ?? ()\n#7  0x0815fb05 in ?? ()\n#8  0x08170507 in ?? ()\n#9  0x08175cb1 in _PyObject_CallMethod_SizeT ()\n#10 0x08164851 in ?? ()\n#11 0x080a3a36 in PyEval_EvalFrameEx ()\n#12 0x080a3a53 in PyEval_EvalFrameEx ()\n#13 0x080a43c8 in PyEval_EvalCodeEx ()\n#14 0x080a466f in PyEval_EvalCode ()\n#15 0x080c6e9d in PyRun_FileExFlags ()\n#16 0x080c70c0 in PyRun_SimpleFileExFlags ()\n#17 0x080db537 in Py_Main ()\n#18 0x0805deee in main ()\n(gdb) finish\nRun till exit from #0  0x0012e416 in __kernel_vsyscall ()\n0x0013c483 in __write_nocancel () from /lib/i386-linux-gnu/libpthread.so.0\n...\n
Run Code Online (Sandbox Code Playgroud)\n\n

不幸的是,我现在无法从源代码构建 Python3 并对其进行调试;所以我希望得到知道的人的答复:)

\n\n

干杯!

\n