Znany jest problem w Pythonie, gdzie "close failed in file object destructor" when "Broken pipe" happens on stdout - Python tracker Issue 11380; również widoczne w python - Why does my Python3 script balk at piping its output to head or tail (sys module)? - Stack Overflow.Pomijanie wydruku komunikatu "Wyjątek ... ignorowane" w Pythonie 3
To, co chcę zrobić, to wydrukowanie tego samego niestandardowego komunikatu, gdy wystąpi ten problem, zarówno w Pythonie 2.7, jak i w Pythonie 3+. Więc przygotować skrypt testowy, testprint.py
i uruchom go (Pokazane fragmenty wykonane w 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
Zgodnie z oczekiwaniami z linków powyżej, istnieją dwa różne komunikaty. W Help with a piping error (velocityreviews.com) zaleca się użycie sys.stdout.flush()
, aby zmusić Python 2 do zarejestrowania IOError zamiast tego komunikatu; z tym, mamy:
$ 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, coraz bliżej ... Teraz, droga do „ignoruj” te wyjątki (lub w moim przypadku, wymienić z komunikatem błędu niestandardowego), ma je obsługiwać:
Ignore exceptions - comp.lang.python
> Czy istnieje jakiś sposób, aby [tłumacza] ignorować wyjątki.
Nie. Obsługuj wyjątki lub pisz kod, który nie generuje wyjątków.
... a jako An Introduction to Python - Handling Exceptions zauważyłem, że sposobem na to jest blok try/except. Więc spróbujmy, że:
$ 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, więc spróbuj/z wyjątkiem prac jak oczekuję go dla Pythona 2.7 - ale wtedy, Python 3.2 oba uchwyty zgodnie z oczekiwaniami, i nadal generuje komunikat Exception ... ignored
! W czym tkwi problem - czy "Python 3" nie jest "except IOError
"? Ale musi tak być - w przeciwnym razie nie wydrukowałby niestandardowej wiadomości "Exc:...
"!
A więc - jaki jest tutaj problem i dlaczego Exception ... ignored
nadal jest drukowany w Pythonie 3, nawet jeśli obsługuję wyjątek? I co ważniejsze, jak mam sobie z tym poradzić, aby drukować więcej niż 1?.
Działa na mnie z głową, ogonem, mniej, więcej i niepowtarzalnie, więc wygląda na to, że istnieje konkretny błąd w interakcji z echo w szczególności. Część "Zignorowany wyjątek" faktycznie dzieje się podczas wyłączania interpretera, gdy próbuje ponownie wypłukać standardowe strumienie. – ncoghlan