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