The correct thing to do is to throw a different exception according to the type of error that has occurred, so that the user of the function can capture the different cases in blocks except
different, to treat them differently or at least to be able to produce more informative error messages than a simple "Error".
Different types of errors can occur in your function:
- That the file can not be opened. This is already managed by
open()
and it already raises the appropriate type of exception, only in your code you capture that exception and "delete" it by changing it with an error message.
- That a line does not contain
":"
and therefore when doing linea.split(":")
there is no [1]
element that you try to access. This would be another type of error that we might call "incorrect file format"
- That a line contains a single
":"
, which would not exist the [2]
element that you try to return. This would also be an "incorrect file format".
- That the format of the file is correct, but you do not find within the
rule_name
that you were looking for. This is not really an exception. The function could simply return None
in that case to indicate that it has not found anything. However, if you want to treat it as an exception, since the error is "not found", the most appropriate exception would be LookupError
, which is the same exception that python is based on when you try to access a key in a dictionary that does not exist.
We therefore have three possible errors in your function. Ideally, each type of error should generate a different exception. We can search among the standard Python exceptions to see which ones are the most appropriate for each case, or invent our own exceptions.
If we want to use the python ones, for the previous case I think the appropriate ones would be FileNotFoundError
for the first error, ValueError
for the next two (incorrect format of the file) and LookupError
for the third one (not find the data).
With these ideas the code would look like this:
def get(rule_name, parameter_name):
infile = open("parameters.txt", "r")
# Si el fichero no pudo abrirse, python ya habrá lanzado por si solo FileNotFoundException
# En caso contrario, seguimos:
with infile:
for line in infile:
trozos = line.split(":")
if len(trozos)<3:
raise ValueError("El fichero no tiene el formato correcto")
if line.startswith(rule_name.lower()) and trozos[1] == parameter_name.lower():
return trozos[2]
# Si salimos del bucle, es que no hemos retornado antes, por tanto no hemos encontrado el dato
raise LookupError("No se encuentran los datos buscados")
Now, whoever calls your function, will be able to handle the exceptions at your convenience. For example, the following code shows how to capture together the exceptions related to the file (not found or incorrect format):
if __name__=="__main__":
try:
print(get("aa","THR1"))
except (FileNotFoundError, ValueError) as e:
print("Problemas con el fichero")
print(str(e))
except LookupError:
print("No se ha encontrado la regla/parámetro")
In case of errors in the file, the exception is captured in the variable e
, which we can use to show the message contained in the exception itself. In handling LookupError
, however, I ignore the message contained in the exception and change it for another. If the function generates any other exception that is not one of those three, since I am not handling the previous example, it would cause the interruption of the execution and the dump of the call stack. If you want to avoid that you can capture Exception
, which being the base class of all exceptions, will capture any other exception. It is usually not recommended to do so, however, at least during development, so as not to mask hidden errors.