xticks barplot python exception-handling nested try-catch

python - barplot - Evitando intentar, excepto anidar



pandas plot (4)

Dado un archivo de tipo de archivo desconocido, me gustaría abrir ese archivo con uno de varios controladores. Cada uno de los controladores genera una excepción si no puede abrir el archivo. Me gustaría probarlos todos y si ninguno tiene éxito, lanzar una excepción.

El diseño que se me ocurrió es

filename = ''something.something'' try: content = open_data_file(filename) handle_data_content(content) except IOError: try: content = open_sound_file(filename) handle_sound_content(content) except IOError: try: content = open_image_file(filename) handle_image_content(content) except IOError: ...

Esta cascada no parece ser la forma correcta de hacerlo.

¿Alguna sugerencia?


¿Está el control completamente fuera de cuestión?

>>> import urllib >>> from mimetypes import MimeTypes >>> guess = MimeTypes() >>> path = urllib.pathname2url(target_file) >>> opener = guess.guess_type(path) >>> opener (''audio/ogg'', None)

Sé que try/except y eafp es muy popular en Python, pero hay veces en que una coherencia tonta solo interfiere con la tarea en cuestión.

Además, un ciclo try / except de IMO puede no romperse necesariamente por las razones que esperas, y como otros han señalado necesitarás informar los errores de una manera significativa si quieres ver lo que realmente está sucediendo mientras intentas itere sobre los abridores de archivos hasta que tenga éxito o falle. De cualquier manera, hay un código introspectivo que se escribe: bucear en try / excepts y obtener uno significativo, o leer la ruta del archivo y usar un verificador de tipos, o incluso simplemente dividir el nombre del archivo para obtener la extensión ... in the face of ambiguity, refuse the temptation to guess .


Al igual que los demás, también recomiendo usar un bucle, pero con un alcance más estricto try/except ámbitos.

Además, siempre es mejor volver a generar la excepción original para conservar información adicional sobre el error, incluido el rastreo.

openers_handlers = [ (open_data_file, handle_data_context) ] def open_and_handle(filename): for i, (opener, handler) in enumerate(openers_handlers): try: f = opener(filename) except IOError: if i >= len(openers_handlers) - 1: # all failed. re-raise the original exception raise else: # try next continue else: # successfully opened. handle: return handler(f)


Puede usar administradores de contexto:

class ContextManager(object): def __init__(self, x, failure_handling): self.x = x self.failure_handling = failure_handling def __enter__(self): return self.x def __exit__(self, exctype, excinst, exctb): if exctype == IOError: if self.failure_handling: fn = self.failure_handling.pop(0) with ContextManager(fn(filename), self.failure_handling) as context: handle_data_content(context) return True filename = ''something.something'' with ContextManager(open_data_file(filename), [open_sound_file, open_image_file]) as content: handle_data_content(content)


Tal vez pueda agrupar todos los controladores y evaluarlos en un bucle forrando una excepción al final si ninguno tuvo éxito. También puede aferrarse a la excepción planteada para recuperar parte de la información como se muestra aquí:

filename = ''something.something'' handlers = [(open_data_file, handle_data_context), (open_sound_file, handle_sound_content), (open_image_file, handle_image_content) ] for o, h in handlers: try: o(filename) h(filename) break except IOError as e: pass else: # Raise the exception we got within. Also saves sub-class information. raise e