¿Cómo debo manejar correctamente las excepciones en Python3?

No puedo entender qué tipo de excepciones debo manejar ‘aquí y ahora’, y qué tipo de excepciones debo volver a boost o simplemente no manejar aquí, y qué hacer con ellas más adelante (en el nivel superior). Por ejemplo: escribí la aplicación cliente / servidor usando python3 con comunicación ssl. Se supone que el cliente debe verificar los archivos sobre cualquier diferencia en ellos, y si existe diff, debe enviar este archivo ‘actualizado’ al servidor.

class BasicConnection: #blablabla def sendMessage(self, sock, url, port, fileToSend, buffSize): try: sock.connect((url, port)) while True: data = fileToSend.read(buffSize) if not data: break sock.send(data) return True except socket.timeout as toErr: raise ConnectionError("TimeOutError trying to send File to remote socket: %s:%d" % (url,port)) from toErr except socket.error as sErr: raise ConnectionError("Error trying to send File to remote socket: %s:%d" % (url,port)) from sErr except ssl.SSLError as sslErr: raise ConnectionError("SSLError trying to send File to remote socket: %s:%d" % (url,port)) from sslErr finally: sock.close() 

¿Es la forma correcta de usar excepciones en Python? El problema es: ¿qué pasa si file.read () lanza IOError? ¿Debo manejarlo aquí, o simplemente no hacer nada y atraparlo más tarde? ¿Y muchas otras posibles excepciones?

  1. El cliente usa esta clase (BasicConnection) para enviar archivos actualizados al servidor:
 class PClient(): def __init__(self, DATA): '''DATA = { 'sendTo' : {'host':'','port':''}, 'use_ssl' : {'use_ssl':'', 'fileKey':'', 'fileCert':'', 'fileCaCert':''}, 'dirToCheck' : '', 'localStorage': '', 'timeToCheck' : '', 'buffSize' : '', 'logFile' : ''} ''' self._DATA = DATA self._running = False self.configureLogging() def configureLogging(self): #blablabla def isRun(self): return self._running def initPClient(self): try: #blablabla return True except ConnectionError as conErr: self._mainLogger.exception(conErr) return False except FileCheckingError as fcErr: self._mainLogger.exception(fcErr) return False except IOError as ioErr: self._mainLogger.exception(ioErr) return False except OSError as osErr: self._mainLogger.exception(osErr) return False def startPClient(self): try: self._running = True while self.isRun(): try : self._mainLogger.debug("Checking differences") diffFiles = FileChecker().checkDictionary(self._dict) if len(diffFiles) != 0: for fileName in diffFiles: try: self._mainLogger.info("Sending updated file: %s to remote socket: %s:%d" % (fileName,self._DATA['sendTo']['host'],self._DATA['sendTo']['port'])) fileToSend = io.open(fileName, "rb") result = False result = BasicConnection().sendMessage(self._sock, self._DATA['sendTo']['host'], self._DATA['sendTo']['port'], fileToSend, self._DATA['buffSize']) if result: self._mainLogger.info("Updated file: %s was successfully delivered to remote socket: %s:%d" % (fileName,self._DATA['sendTo']['host'],self._DATA['sendTo']['port'])) except ConnectionError as conErr: self._mainLogger.exception(conErr) except IOError as ioErr: self._mainLogger.exception(ioErr) except OSError as osErr: self._mainLogger.exception(osErr) self._mainLogger.debug("Updating localStorage %s from %s " %(self._DATA['localStorage'], self._DATA['dirToCheck'])) FileChecker().updateLocalStorage(self._DATA['dirToCheck'], self._DATA['localStorage']) self._mainLogger.info("Directory %s were checked" %(self._DATA['dirToCheck'])) time.sleep(self._DATA['timeToCheck']) except FileCheckingError as fcErr: self._mainLogger.exception(fcErr) except IOError as ioErr: self._mainLogger.exception(ioErr) except OSError as osErr: self._mainLogger.exception(osErr) except KeyboardInterrupt: self._mainLogger.info("Shutting down...") self.stopPClient() except Exception as exc: self._mainLogger.exception(exc) self.stopPClient() raise RuntimeError("Something goes wrong...") from exc def stopPClient(self): self._running = False 

¿Es correcto? ¿Puede ser alguien pasar su propio tiempo y simplemente ayudarme a entender el estilo python de manejo de excepciones? No puedo entender qué hacer con excepciones tales como NameError, TypeError, KeyError, ValueError … y así sucesivamente ……. Se pueden lanzar a cualquier statement, en cualquier momento … y qué hacer Con ellos, si quiero registrar todo.

  1. ¿Y qué información deberían registrar las personas normalmente? Si se produce un error, ¿qué información sobre él debo registrar? ¿Todo el rastreo, o solo un mensaje relevante al respecto o algo más?

  2. Espero que alguien me ayude. Muchas gracias.

En general, debe “capturar” las excepciones que espera que ocurran (porque pueden ser causadas por un error del usuario u otros problemas ambientales fuera del control de su progtwig), especialmente si sabe lo que su código podría hacer al respecto. . Solo dar más detalles en un informe de errores es un problema marginal, aunque las especificaciones de algunos progtwigs pueden requerir hacerlo (por ejemplo, un servidor de larga ejecución que no debe fallar debido a dichos problemas, sino que más bien registra una gran cantidad de información de estado, use una explicación resumida y siga trabajando para futuras consultas).

NameError , TypeError , KeyError , ValueError , SyntaxError , AttributeError , etc., se deben a errores en el progtwig: errores, no problemas fuera del control del progtwigdor. Si está liberando una biblioteca o un marco, de modo que otro código fuera de su control llamará a su código, entonces es probable que esos errores estén en ese otro código; Normalmente, debería dejar que la excepción se propague para ayudar al otro progtwigdor a depurar sus propios errores. Si está lanzando una aplicación, es dueño de los errores y debe elegir la estrategia que le ayude a encontrarlos.

Si sus errores aparecen mientras un usuario final está ejecutando el progtwig, debe registrar una gran cantidad de información de estado y dar al usuario una explicación resumida y disculpas (tal vez con una solicitud para enviarle la información de registro, si no puede automatice eso, o, al menos, solicite permiso antes de enviar algo desde la máquina del usuario a la suya). Es posible que pueda guardar parte del trabajo del usuario hasta ahora, pero a menudo (en un progtwig que se sabe que tiene errores) puede que no funcione de todos modos.

La mayoría de los errores deberían aparecer durante sus propias pruebas, por supuesto; en ese caso, la propagación de la excepción es útil, ya que puede conectarla a un depurador y explorar los detalles del error.

A veces, algunas excepciones como estas aparecen solo porque “es más fácil pedir perdón que permiso” (EAFP), una técnica de progtwigción perfectamente aceptable en Python. En ese caso, por supuesto, debe manejarlos a la vez. Por ejemplo:

 try: return mylist[theindex] except IndexError: return None 

aquí puede esperar que el theindex sea ​​generalmente un índice válido en mylist , pero ocasionalmente fuera de los mylist de mylist , y este último caso, por la semántica de la aplicación hipotética a la que pertenece este fragmento, no es un error, solo un poco la anomalía se arregla considerando que la lista se extiende conceptualmente en ambos lados con un número infinito de None . Es más fácil simplemente probar / excepto que verificar correctamente los valores positivos y negativos del índice (y más rápido, si está fuera de los límites es algo realmente raro).

De manera similar, los casos apropiados para KeyError y AttributeError ocurren con menos frecuencia, gracias a la getattr incorporada getattr y get de dicts (que le permiten proporcionar un valor predeterminado), collections.defaultdict , etc; pero las listas no tienen un equivalente directo de esos, por lo que el try / except se ve más frecuentemente para IndexError .

Tratar de detectar errores de syntax, errores de tipo, errores de valor, errores de nombre, etc. es un poco más raro y más controvertido, aunque seguramente sería apropiado si el error se diagnosticara en un “complemento”, fuera del código de un tercero. su control que su marco / aplicación está intentando cargar y ejecutar dinámicamente (de hecho, ese es el caso en el que está suministrando una biblioteca o similar y necesita coexistir pacíficamente con el código fuera de su control, que bien podría tener errores). Los errores de tipo y valor a veces pueden ocurrir dentro de un patrón de EAFP, por ejemplo, cuando intenta sobrecargar una función para aceptar una cadena o un número y comportarse de manera ligeramente diferente en cada caso, la captura de dichos errores puede ser mejor que intentar verificar tipos: pero el concepto mismo de funciones sobrecargadas de este modo es a menudo bastante dudoso.

De vuelta a los “errores de usuario y medioambientales”, los usuarios inevitablemente cometen errores cuando le dan su opinión, indican un nombre de archivo que realmente no está alrededor (o que no tiene permiso para leer o escribir si eso es lo que debe) estar haciendo), y así sucesivamente: todos estos errores deben, por supuesto, detectarse y dar como resultado una explicación clara para el usuario acerca de lo que está mal, y otra oportunidad para obtener la información correcta. Algunas veces, las redes se caen, las bases de datos u otros servidores externos pueden no responder como se espera, y así sucesivamente: a veces vale la pena detectar estos problemas y volver a intentarlo (quizás después de una pequeña espera) tal vez con una indicación al usuario sobre lo que está mal, por ejemplo puede haber desconectado accidentalmente un cable y usted quiere darles la oportunidad de arreglar las cosas y decirle cuándo debe intentarlo de nuevo), a veces (especialmente en progtwigs desatendidos de larga duración) no hay nada que pueda hacer, excepto un apagado ordenado (y un registro detallado) de todos los aspectos posiblemente relevantes del medio ambiente).

Entonces, en resumen, la respuesta al título de tu Q es “depende” ;-). Espero haber sido de utilidad para enumerar muchas de las situaciones y aspectos en los que puede depender, y para recomendar cuál es la actitud más útil a tener en cuenta en relación con estos temas.

Para empezar, no necesitas ningún _mainLogger. Si desea detectar excepciones, tal vez iniciar sesión o enviarlas por correo electrónico o lo que sea, hacerlo al nivel más alto posible, ciertamente no dentro de esta clase.

Además, definitivamente no desea convertir todas las excepciones a un RuntimeError. Déjalo emerger. El método stopClient () no tiene ningún propósito en este momento. Cuando lo tenga, lo veremos ..

Básicamente, podría envolver el ConnectionError, IOError y OSError juntos (como, volver a subir como otra cosa), pero no mucho más que eso …