CrazyCoder
CrazyCoder

Reputation: 517

Specific exception handling

I am writing a program that calculates the compound interest using the formula: P(1 + i)n

The principal, interest and number of years are obtained from the user input.

I have written the following method:

def is_valid_entries(principle, int_rate, years):
    try:
        #Convert the inputs from string to respective data type
        principal_float = float(principle)
        rate_float = float(int_rate)
        years_int = int(years)
        
        if not (0 < rate_float < 1.0):
            return False, "The interest rate must be between 0.00 to 1.00"

        return True, (principal_float, rate_float, years_int)
    except ValueError:
        return False, "Could not convert data to the appropriate data type"
    except:
        return False, "Unknown error"

However, my issue is I want to be very specific when i report exception. For instance, if there's a conversion error on principal, I want to report that there's an error in converting the principal and the same logic follows with interest rate and years. Please let me know how this can be done in exception handling or if there's a better way to write this.

Upvotes: 0

Views: 115

Answers (2)

Tomerikoo
Tomerikoo

Reputation: 19395

In general, you will have to minimize your try block to specific lines, to look something like this:

def is_valid_entries(principle, int_rate, years):
    #Convert the inputs from string to respective data type
    try:
        principal_float = float(principle)
    except ValueError:
        return False, "Could not convert principal to the appropriate data type"
    try:
        rate_float = float(int_rate)
    except ValueError:
        return False, "Could not convert rate to the appropriate data type"
    try:
        years_int = int(years)
    except ValueError:
        return False, "Could not convert years to the appropriate data type"
        
    if not (0 < rate_float < 1.0):
        return False, "The interest rate must be between 0.00 to 1.00"

    return True, (principal_float, rate_float, years_int)

Of course, as you can see this is horrible. A hint for improvement is repeating code == functions, so a good idea can be to wrap this in a function:

def number_conversion(string, type, name):
    try:
        return type(string)
    except ValueError:
        raise ValueError(f"Could not convert {name} to {type().__class__.__name__}")

And now your main code can look like:

def is_valid_entries(principle, int_rate, years):
    #Convert the inputs from string to respective data type
    try:
        principal_float = number_conversion(principle, float, "principle")
        rate_float = number_conversion(int_rate, float, "rate")
        years_int = number_conversion(years, int, "years")
    except ValueError as ve:
        return False, ve.message
        
    if not (0 < rate_float < 1.0):
        return False, "The interest rate must be between 0.00 to 1.00"

    return True, (principal_float, rate_float, years_int)

This way you get a specific message according to each input.

* I removed the blank except as there are no other exceptions that will rise in this code

Upvotes: 1

Matt Blaha
Matt Blaha

Reputation: 977

You're just missing the "raise" keyword. You probably don't want to wrap this whole thing in a try block like that, you just want to use raise instead of return in some places.

For example where you have:

    if not (0 < rate_float < 1.0):
            return False, "The interest rate must be between 0.00 to 1.00"

You could instead say:

    if not (0 < rate_float < 1.0):
            raise ValueError("The interest rate must be between 0.00 to 1.00")

That will raise a value error with that message that you are returning as a string. If someone calls your function in a try block, they can handle the ValueError exception.

https://docs.python.org/3/tutorial/errors.html

Upvotes: 2

Related Questions