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
并运行它(显示在bash
Ubuntu 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,越来越近......现在,顺便给"忽略"这些例外(或者对于我来说,有一个自定义错误消息替换),是来处理它们:
>有没有办法让[解释器]忽略异常.
不.处理异常或编写不生成异常的代码.
...作为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
也不会得到了印?
关于此问题还有一些注意事项 - 问题仍未解决......首先:
\n\n问题 6294:改进关闭异常忽略消息 - Python 跟踪器
\n\n\n\n\n此错误消息是在 PyErr_WriteUnraisable 中生成的,它是从许多上下文中调用的,包括 __del__ 方法。在关闭期间调用的 __del__ 方法很可能是生成您所说的错误的原因,但据我所知, __del__ 方法无法知道它是在关闭期间被调用的。因此,建议的对该消息的修复将不起作用。[....]
\n
\n 但是,因为这是一条消息,您甚至无法捕获它\n 更改它应该是完全安全的。
嗯,谢谢你的这个消息,你不能陷入困境,非常方便。我相信这在某种程度上与del ()中忽略打印到 stderr 的异常有关- Stack Overflow,尽管该帖子(显然)讨论了自定义__del__
方法。
使用以下一些资源:
\n\n\n\n...我修改了脚本,因此我重载了所有可能的处理程序,以查看是否有空间可以“处理”此异常,因此它不会被“忽略”:
\n\nimport 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
消息......但我不知道有任何这样的事物。
最后,当尝试使用以下资源进行调试时,这些资源非常有用gdb
:
...因为我没有python3-dbg
,所以所有这些都简化为逐步执行机器指令(layout asm
在 中gdb
,然后按 Ctrl-X + A),这并没有真正告诉我太多信息。但以下是如何触发该问题gdb
:
在一个终端中:
\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 归档时间: |
|
查看次数: |
3611 次 |
最近记录: |