2016-01-11 14 views
5

Próbuję napisać kod, aby złapać błąd zepsutej rury. Kod powinien działać w Pythonie 2.x i Pythonie 3.x.Złapać przerwaną rurę w Pythonie 2 I Pythonie 3

Pythona 2.xa pęknięcia przewodu jest reprezentowany przez socket.error

socket.error: [Errno 32] Broken pipe 

to zmieniono w Pythonie 3.x - złamany rury teraz jest BrokenPipeError

BrokenPipeError: [Errno 32] Broken pipe 

również składnia obsługa wyjątków zmieniła się nieco (zob. https://stackoverflow.com/a/34463112/263589), więc potrzebuję czegoś takiego:

try: 
    do_something() 
except BrokenPipeError as e: # implies Python 3.x 
    resolve_for_python2() 
except socket.error as e: 
    if sys.version_info[0] == 2: # this is necessary, as in Python >=3.3 
           # socket.error is an alias of OSError 
           # https://docs.python.org/3/library/socket.html#socket.error 
     resolve_for_python3() 
    else: 
     raise 

Istnieje (przynajmniej) jeden pozostały problem: w Pythonie 2.x nie ma numeru BrokenPipeError, więc w przypadku wyjątku w do_something() Python 2.x rzuciłby inny wyjątek i narzekałby, że nie zna BrokenPipeError. Ponieważ socket.error jest przestarzałe w Pythonie 3.x, podobny problem może pojawić się w Pythonie 3.x w najbliższej przyszłości.

Co mogę zrobić, aby ten kod działał w Pythonie 2.x i Pythonie 3.x?

+0

Zobacz http://python-future.org/compatible_idioms.html, wyświetlają obsługę wyjątku. – MKesper

+1

http://newbebweb.blogspot.in/2012/02/python-head-ioerror-errno-32-broken.html tutaj jest –

+0

Dziękujemy! Ale http://python-future.org/compatible_idioms.html#catching-exceptions nie wyjaśnia, jak uchwycić wyjątek, który nie istnieje ani w Pythonie 2, ani w Pythonie 3, ale jest obowiązkowy w drugiej wersji. – speendo

Odpowiedz

3

Jeśli wszystko czego dbają o to zepsutymi błędami w rurach, wtedy możesz chcieć złapać socket.error i po prostu sprawdzić, czy to rzeczywiście jest zepsuty błąd rury.

Możesz to zrobić za pomocą atrybutu wyjątku: errno, który jest obecny zarówno w Pythonie 2, jak i Pythonie 3, co oznacza, że ​​nie potrzebujesz innej logiki Pythona 2 vs. 3 (argumentowałabym, że intencja jest trochę jaśniejsze w ten sposób):

import socket 
import errno 


try: 
    do_something() 
except socket.error as e: 
    if e.errno != errno.EPIPE: 
     # Not a broken pipe 
     raise 
    do_something_about_the_broken_pipe() 

Jeśli dbasz o więcej niż połamanych rur, odpowiedź thefourtheye jest właściwe i idiomatyczne.

+0

Dziękujemy! Martwi mnie to trochę, że 'socket.error' jest przestarzałe w Pythonie 3. Więc w przypadku aktualizacji interpretera Pythona 3 może być inny problem w (najbliższej) przyszłości ... – speendo

+1

@speendo istnieją dziesiątki odniesień do 'socket.error' * w samej bibliotece standardowej Python *. Jest przestarzałe, jasne, ale nie zniknie. Usunięcie 'socket.error' byłoby bezsensowną zmianą zerwania, o czym programiści Pythona publicznie stwierdzili, że będą unikać w przyszłości. Gdyby udało się go usunąć (w ciągu kilku dekad ?!;)), błąd byłby trywialny, by go zidentyfikować i naprawić, i na tym etapie prawdopodobnie i tak nie będzie już obsługiwać Pythona 2. –

+0

ma sens .... – speendo

1

Można spróbować użyć BrokenPipeError a jeśli rzuca NameError, a następnie powróci do socket.error, jak to

import socket 
try: 
    expected_error = BrokenPipeError 
except NameError: 
    expected_error = socket.error 

a następnie używać go jak ten

try: 
    1 == 2 
except expected_error as ex: 
    # Handle the actual exception here