¿Cuál es una mejor práctica en una función definida por el usuario en Python: raise
una excepción o return None
? Por ejemplo, tengo una función que busca el archivo más reciente en una carpeta.
def latestpdf(folder):
# list the files and sort them
try:
latest = files[-1]
except IndexError:
# Folder is empty.
return None # One possibility
raise FileNotFoundError() # Alternative
else:
return somefunc(latest) # In my case, somefunc parses the filename
Otra opción es dejar la excepción y manejarla en el código de la persona que llama, pero creo que es más claro lidiar con FileNotFoundError
un IndexError
. ¿O es una mala forma volver a generar una excepción con un nombre diferente?
python
exception-handling
parcydarks
fuente
fuente
Respuestas:
Realmente es una cuestión de semántica. ¿Qué
foo = latestpdf(d)
significa ?¿Es perfectamente razonable que no haya un archivo más reciente? Entonces seguro, devuelve None.
¿Espera encontrar siempre un archivo más reciente? Plantee una excepción. Y sí, volver a plantear una excepción más apropiada está bien.
Si esta es solo una función general que se supone que se aplica a cualquier directorio, haría lo primero y devolvería Ninguno. Si, por ejemplo, el directorio está destinado a ser un directorio de datos específico que contiene el conjunto de archivos conocido de una aplicación, plantearía una excepción.
fuente
None
.Haría un par de sugerencias antes de responder su pregunta, ya que puede responderla por usted.
latestpdf
significa muy poco para cualquiera, pero al revisar su función selatestpdf()
obtiene el último pdf. Sugeriría que lo nombregetLatestPdfFromFolder(folder)
.Tan pronto como hice esto, quedó claro qué debería devolver. Si no hay un pdf, plantee una excepción. Pero espera ahí más ...
for folder in folders: try: latest = getLatestPdfFromFolder(folder) results = somefuc(latest) except IOError: pass
¡Espero que esto ayude!
fuente
get_latest_pdf_from_folder
. De hecho, Pep8: "Los nombres de funciones deben estar en minúsculas, con palabras separadas por guiones bajos según sea necesario para mejorar la legibilidad".Por lo general, prefiero manejar las excepciones internamente (es decir, intentar / excepto dentro de la función llamada, posiblemente devolviendo None) porque Python se escribe dinámicamente. En general, lo considero un juicio de una forma u otra, pero en un lenguaje escrito dinámicamente, hay pequeños factores que inclinan la balanza a favor de no pasar la excepción a la persona que llama:
if val is None
es un poco más fácil queexcept ComplicatedCustomExceptionThatHadToBeImportedFromSomeNameSpace
. En serio, odio tener que recordar escribirfrom django.core.exceptions import ObjectDoesNotExist
en la parte superior de todos mis archivos de django solo para manejar un caso de uso realmente común. En un mundo de tipos estáticos, deje que el editor lo haga por usted.Honestamente, sin embargo, siempre es una decisión de criterio, y la situación que está describiendo, donde la función llamada recibe un error que no puede ayudar, es una excelente razón para volver a generar una excepción que sea significativa. Tiene la idea exacta correcta, pero a menos que sea una excepción, proporcionará información más significativa en un seguimiento de pila que
AttributeError: 'NoneType' object has no attribute 'foo'
que, nueve de cada diez veces, es lo que verá la persona que llama si devuelve un Ninguno sin controlar, no se moleste.
(Todo esto me hace desear que las excepciones de Python tuvieran los
cause
atributos por defecto, como en Java, lo que le permite pasar excepciones a nuevas excepciones para que pueda volver a lanzar todo lo que quiera y nunca perder la fuente original del problema).fuente
con Python 3.5 escribiendo :
La función de ejemplo al devolver None será:
def latestpdf(folder: str) -> Union[str, None]
y al plantear una excepción será:
def latestpdf(folder: str) -> str
la opción 2 parece más legible y pitónica
(+ opción para agregar un comentario a la excepción como se indicó anteriormente).
fuente
Union[str, None]
debería serOptional[str]
En general, diría que se debe lanzar una excepción si ha ocurrido algo catastrófico del que no se puede recuperar (es decir, su función se ocupa de algún recurso de Internet al que no se puede conectar), y debe devolver Ninguno si su función realmente debería devolver algo pero no sería apropiado devolver nada (es decir, "Ninguno" si su función intenta hacer coincidir una subcadena en una cadena, por ejemplo).
fuente