2016-01-11 15 views
5

Provo a scrivere del codice per catturare un errore di tubo rotto. Il codice dovrebbe essere eseguito in Python 2.xe Python 3.x.Catch Broken Pipe in Python 2 AND Python 3

In Python 2.xa tubo rotto è rappresentato da un socket.error

socket.error: [Errno 32] Broken pipe 

Ciò è stato cambiato in Python 3.x - un tubo rotto ora è un BrokenPipeError

BrokenPipeError: [Errno 32] Broken pipe 

Anche la sintassi la gestione delle eccezioni è leggermente cambiata (vedi https://stackoverflow.com/a/34463112/263589), quindi quello che devo fare è qualcosa di simile:

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 

C'è (almeno) un problema rimanente: In Python 2.x non c'è BrokenPipeError, quindi ogni volta che c'è un'eccezione in do_something() Python 2.x lancia un'altra eccezione e si lamenta che non sa BrokenPipeError. Poiché socket.error è deprecato in Python 3.x, un problema simile potrebbe sorgere in Python 3.x nel prossimo futuro.

Cosa posso fare per far funzionare questo codice in Python 2.xe Python 3.x?

+0

Dai un'occhiata a http://python-future.org/compatible_idioms.html, mostrano la gestione delle eccezioni. – MKesper

+1

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

+0

Grazie! Ma http://python-future.org/compatible_idioms.html#catching-exceptions non spiega come rilevare un'eccezione che non esiste in Python 2 o Python 3 ma è obbligatoria nell'altra versione. – speendo

risposta

3

Se tutto ciò che interessa sono errori di pipe rotte, quindi potresti voler catturare socket.error e controllare semplicemente se si tratta davvero di un errore di pipe rotto.

È possibile utilizzare l'attributo errno dell'eccezione, che è presente in Python 2 e Python 3, il che significa che non è necessaria una logica diversa da Python 2 a 3 (direi che l'intento è un po ' più chiaro in questo modo):

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() 

Se non si preoccupano più di tubi rotti, la risposta di thefourtheye è appropriato e idiomatica.

+0

Grazie! Mi preoccupa un po 'che 'socket.error' sia deprecato in Python 3. Quindi, nel caso in cui aggiorni il mio interprete Python 3, potrebbe esserci un altro problema nel (vicino) futuro ... – speendo

+1

@speendo ci sono dozzine di riferimenti a 'socket.error' * nella libreria standard Python stessa *. È deprecato, certo, ma non sta andando via. Rimozione di 'socket.error' sarebbe un'inutile rottura, che è qualcosa che gli sviluppatori core di Python hanno dichiarato pubblicamente che eviteranno in futuro. Se finisse rimosso (tra qualche decennio?!;)), L'errore sarebbe banale da identificare e correggere, ea quel punto probabilmente non avresti più supportato Python 2. –

+0

ha senso .... – speendo

1

Puoi provare a utilizzare BrokenPipeError e se si getta un NameError, poi ripiegare a socket.error, come questo

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

e quindi utilizzarlo come questo

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