Search code examples
pythonexceptiontry-catch

How can I make catching exceptions assign a variable a certain value without constantly repeating the code?


I'm going to clarify.

I'm logging 6 different variables and some of them have errors (what kind of error doesn't matter). When that error occurs, I just want that specific variable to be put to "NA".

Here's an idea of what I mean:

myDict = []
for i in data:
    try:
        eye = ...
        nose = ...
        mouth = ...
        ear = ...
        hair = ...
        tongue = ...
        
        myDict.append([eye, nose, mouth, ear, hair, tongue])

   except eye:
        eye = "NA"
        myDict.append([eye, nose, mouth, ear, hair, tongue])
  
   except nose:
        nose = "NA"
        myDict.append([eye, nose, mouth, ear, hair, tongue])

   except mouth:
        mouth = "NA"
        myDict.append([eye, nose, mouth, ear, hair, tongue])

   ...

Do I have to do an "except" for every single variable? Is there some way I could just do "except whatever variable has error, assign its value to "NA" and append normally"?

I also don't know what happens if there's an error in more than 1 variable.

The fundamental idea is: "if there's an error for a variable(S), just assign it/them the value "NA" and keep appending.


Solution

  • Here's an example of an approach that will do what you're asking.

    First some comments:

    • You have used the term "error", but your sample code uses try/except, so I will assume that each "error" results in an exception being raised.
    • In the code below, I use an artificially simplified scenario in which the assignment to each variable has the possibility of raising an exception with a similar name, and I have created these as user-defined exceptions; in reality, you may not need to define these and would instead replace the parenthesized exception types in the sample code with the actual exceptions that you want to catch.
    • You have something called myDict which is actually a python list; I will rename this result in the code below to avoid confusion.

    The logic of the code below can be summarized as:

    • Instead of assigning directly to named variables (as in the code in your question), iterate through a list of variable tags (strings like 'eye', 'nose', etc.) in an inner loop which has a try/except block inside it;
    • Within this inner list, do the work for the given tag (the same work that would be done by eye = ... or mouth = ... in your question) and append the result to a list L, unless an exception is raised, in which case the try block instead appends "NA" to L;
    • This means that whether or not there are errors (more accurately, whether or not exceptions are raised), L will have a value appended to it for each variable tag;
    • At the end of the inner loop, append L to the result.

    Here is the sample code:

    class eye_exception(Exception):
        pass
    class nose_exception(Exception):
        pass
    class mouth_exception(Exception):
        pass
    class ear_exception(Exception):
        pass
    class hair_exception(Exception):
        pass
    class tongue_exception(Exception):
        pass
    
    
    def getValueForEye(i):
        return "eye_value" + str(i)
    def getValueForNose(i):
        return "nose_value" + str(i)
    def getValueForMouth(i):
        if i % 3 == 0:
            raise mouth_exception()
        return "mouth_value" + str(i)
    def getValueForEar(i):
        return "ear_value" + str(i)
    def getValueForHair(i):
        if i % 3 != 0:
            raise hair_exception()
        return "hair_value" + str(i)
    def getValueForTongue(i):
        return "tongue_value" + str(i)
    
    data = [1, 2, 3]
    
    result = []
    for i in data:
        L = []
        for key in ['eye', 'nose', 'mouth', 'ear', 'hair', 'tongue']: 
            try:
                match key:
                    case 'eye':
                         value = getValueForEye(i)
                    case 'nose':
                         value = getValueForNose(i)
                    case 'mouth':
                         value = getValueForMouth(i)
                    case 'ear':
                         value = getValueForEar(i)
                    case 'hair':
                         value = getValueForHair(i)
                    case 'tongue':
                         value = getValueForTongue(i)
                L.append(value)
            except (eye_exception, nose_exception, mouth_exception, ear_exception, hair_exception, tongue_exception):
                L.append("NA")
        result.append(L)
    

    Sample result:

    ['eye_value1', 'nose_value1', 'mouth_value1', 'ear_value1', 'NA', 'tongue_value1']
    ['eye_value2', 'nose_value2', 'mouth_value2', 'ear_value2', 'NA', 'tongue_value2']
    ['eye_value3', 'nose_value3', 'NA', 'ear_value3', 'hair_value3', 'tongue_value3']
    

    Alternatively, if you are using a version of python that does not support the match/case construct, or you simply prefer not to use it, you can replace the loop above with this code which uses a dictionary to map from variable tag to function:

    funcDict = {
        'eye':getValueForEye, 
        'nose':getValueForNose, 
        'mouth':getValueForMouth, 
        'ear':getValueForEar, 
        'hair':getValueForHair, 
        'tongue':getValueForTongue
    }
    for i in data:
        L = []
        for key, func in funcDict.items(): 
            try:
                value = func(i)
                L.append(value)
            except (eye_exception, nose_exception, mouth_exception, ear_exception, hair_exception, tongue_exception):
                L.append("NA")
        result.append(L)