Có một vấn đề đã biết trong Python, trong đó "close failed in file object destructor" when "Broken pipe" happens on stdout - Python tracker Issue 11380; cũng được thấy trong python - Why does my Python3 script balk at piping its output to head or tail (sys module)? - Stack Overflow.Ngăn chặn bản in của thông báo "Ngoại lệ ... bị bỏ qua" trong Python 3
Điều tôi muốn làm là in ra cùng một thông báo tùy chỉnh khi sự cố này xảy ra, trong cả Python 2.7 và Python 3+. Vì vậy, tôi chuẩn bị một kịch bản kiểm tra, testprint.py
và chạy nó (đoạn trích thể hiện thực hiện trong 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
Đúng như dự đoán từ các liên kết trên, có hai thông điệp khác nhau. Trong Help with a piping error (velocityreviews.com), bạn nên sử dụng sys.stdout.flush()
để buộc Python 2 đăng ký IOError thay vì thông báo đó; với điều đó, chúng ta có:
$ 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
OK, tiến gần hơn ... Bây giờ, cách để "bỏ qua" những trường hợp ngoại lệ (hoặc trong trường hợp của tôi, thay thế bằng một thông báo lỗi tùy chỉnh), là để xử lý chúng:
Ignore exceptions - comp.lang.python
> có cách nào để làm cho [dịch] bỏ qua trường hợp ngoại lệ.
Không. Hãy xử lý các ngoại lệ hoặc viết mã không tạo ngoại lệ.
... và như An Introduction to Python - Handling Exceptions lưu ý, cách để làm điều đó là khối thử/ngoại trừ. Vì vậy, hãy cố gắng rằng:
$ 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
Ok, vì vậy hãy thử/trừ các công trình như tôi mong đợi nó cho Python 2.7 - nhưng sau đó, Python 3.2 cả hai tay cầm như mong đợi, và vẫn tạo ra một thông điệp Exception ... ignored
! Có vấn đề gì - không phải là "except IOError
" đủ cho Python 3? Nhưng nó phải được - nếu không nó sẽ không có in thông báo "Exc:...
" tùy chỉnh!
Vì vậy, vấn đề ở đây là gì và tại sao Exception ... ignored
vẫn được in bằng Python 3, ngay cả khi tôi đang xử lý ngoại lệ? Và quan trọng hơn, làm thế nào để xử lý nó để Exception ... ignored
không không được in nữa?
Nó làm việc cho tôi với đầu, đuôi, ít hơn, độc đáo hơn và có vẻ như có một lỗi thực sự trong tương tác với tiếng vang nói riêng. Phần "Ngoại lệ bị bỏ qua" thực sự xảy ra trong khi tắt thông dịch khi nó cố gắng tuôn ra các luồng chuẩn một lần nữa. – ncoghlan