1

TL;DR: Why are my exceptions triggering only in certain situations, despite the fact that it is the same error?

The code successfully catches a NameError with an all numerical argument. So if someone mistakenly inputs a number instead of an operator, it gives them the correct exception error message. However, my code fails to catch other exceptions, and I'm unsure why.

For example:

print(better_calc(5, 5, 5))

This returns the desired exception message of

5 5 5 = Error: Name error. Please check your input

However, it does not catch other errors. Instead, it terminates the programme. For example,

print(better_calc(5, g, 5))

This returns ''NameError: name 'g' is not defined'', without triggering the exception or the exception message.

Similarly

print(better_calc(5, *, 5))

This returns ''SyntaxError: invalid syntax'', without triggering the exception or the exception message.

I realize that if I included quotation marks on the operator, that the code would work, however, my goal is to trigger the exceptions.

def better_calc(num1, op, num2):
    try:
        if op == "+":
            result = num1+num2
        elif op == "-":
            result = num1-num2
        elif op == "*":
            result = num1*num2
        elif op == "/":
            num1/num2
    except NameError:
        print(f"Error: Name error. Please check your input")
    except UnboundLocalError:
        print(f"Error: Value error. Please check your input")
    except SyntaxError:
        print(f"Error: Syntax Error. Please check your input")

    print(num1, op, num2, "=")
    return result

print(better_calc(5, 5, 5))
Aaron Daly
  • 27
  • 4
  • 6
    Because the error occurs *outside* your function; it never gets invoked, so cannot possibly catch it. You can't catch syntax errors (outside of exec/eval) because if your code isn't syntactically valid **it cannot run**. – jonrsharpe Jun 16 '20 at 17:10
  • Can you please clarify what you are trying to do? Arguments are evaluated *before* passing them to functions – catching errors *inside* the function does not cover malformed argument syntax or names. Also, operators are not first class – you cannot pass the ``+`` operator to a function, for example. Use ``operator.add`` for that – though your function is written to expect *the string* ``+``, not the corresponding operation. – MisterMiyagi Jun 16 '20 at 17:13
  • Possible dupe: https://stackoverflow.com/questions/4148015/python-try-except-inside-of-function – jonrsharpe Jun 16 '20 at 17:14
  • `SyntaxError`s cannot be caught by code: they are raised during compile time, when Python parses your entire source code into bytecode prior to executing it, not during actual runtime. – jfaccioni Jun 16 '20 at 17:16

1 Answers1

1

Just to consolidate the answers already given in the comments, try/except blocks can only handle errors that are raised between the try: and the first except block.

try:
    # raised exceptions in this block can be caught
    foo = "bar"
except FooError:
    # catches a raised FooError but any exceptions raised here are
    # outside of the try block and will not be handled. Another try/except
    # block could be added here to catch these exceptions
    pass
except Exception as e:
    # a trick to log exceptions but then let the exception run
    print(e)
    raise

The call to the function print(better_calc(5, g, 5)) is outside of the function's try block and will not be caught.

And syntax errors like print(better_calc(5, *, 5)) keep the program from even running, which is definitely outside of the function's try block.

tdelaney
  • 73,364
  • 6
  • 83
  • 116