Home > Software engineering >  Why do I have to import traceback if it already exists?
Why do I have to import traceback if it already exists?

Time:02-10

If I write something in Python and things go awry, I automatically get a traceback.

For example:

#!/usr/bin/env python

print("this will raise a division by zero exception")
print(2/0)

It automatically throws a traceback with the exception

>>> %Run test.py
this will raise a division by zero exception
Traceback (most recent call last):
  File "/home/pi/Desktop/test.py", line 4, in <module>
    print(2/0)
ZeroDivisionError: division by zero
>>> 

Now, let's assume that I don't want the program to crash-and-burn, but I want to handle the exception gracefully - say I need to close files or whatever.

Viz.:

#!/usr/bin/env python
import sys

try:
    print("Assume I'm doing something with a resource, like a file")
    print(". . . and something goes wrong\n")
    print("(This will raise a division by zero exception when I try to \"print(2/0)\")\n")
    print(2/0)

except BaseException as e:
    print(". . . and I want to handle the exception gracefully:\n")
    print("Oops! Something happened! (",e, ")\n")
    sys.exit(0)

Which gets me the expected:

>>> %Run test.py
Assume I'm doing something with a resource, like a file
. . . and something goes wrong

(This will raise a division by zero exception when I try to "print(2/0)")

. . . and I want to handle the exception gracefully:

Oops! Something happened! ( division by zero )

─────────────────────────────────────────────────────────────────────────────────────────────────
Python 3.7.3 (/usr/bin/python3)
>>> 

However, if I try to handle the exception manually, I am told that in order to get the system provided traceback, (the call stack and location of the error), I have to import traceback.

When I do that, I can get all the information I want.

#!/usr/bin/env python
import sys
import traceback

try:
    print("Assume I'm doing something with a resource, like a file")
    print(". . . and something goes wrong\n")
    print("(This will raise a division by zero exception when I try to \"print(2/0)\")\n")
    print(2/0)

except BaseException as e:
    print(". . . and I want to handle the exception gracefully:\n")
    print("Oops! Something happened! (",e, ")\n")
    traceback.print_exc()
    sys.exit(0)

And the expected result:

────────────────────────────────────────────────────────────────────────────────────────────────
Python 3.7.3 (/usr/bin/python3)
>>> %Run test.py
Assume I'm doing something with a resource, like a file
. . . and something goes wrong

(This will raise a division by zero exception when I try to "print(2/0)")

. . . and I want to handle the exception gracefully:

Oops! Something happened! ( division by zero )

Traceback (most recent call last):
  File "/home/pi/Desktop/test.py", line 9, in <module>
    print(2/0)
ZeroDivisionError: division by zero

─────────────────────────────────────────────────────────────────────────────────────────────────
Python 3.7.3 (/usr/bin/python3)
>>> 

"Traceback" appears to already exist as the traceback is automatic on unhandled exceptions

Why do I have to import traceback if I use a try/except block, but don't if I don't?

CodePudding user response:

The traceback reflects the state of the Python Interpreter at a given point during the execution of some code. The Python Interpreter obviously has access to its own state, and shares it with the user, by printing that error message, when an exception is thrown and not handled. It also gives the code access to it – via the traceback module, which is why you need to import it.

CodePudding user response:

The default behavior of Python when an exception is raised that isn't caught in a try...except is to print a traceback and exit. If you do catch it, then the default doesn't happen. You have to decide what to do with it. If you decide to print the traceback you now have to explicitly do it by importing the traceback module and using the methods there. However, that's not strictly necessary as you could just inspect the current traceback object (from sys.exc_info()), and write your own formatter.

CodePudding user response:

The traceback exists, and the interpreter can use it (e.g. print it) , but you can only use it if you import it. If you do not use a try/except block you do not have a chance to import it.

CodePudding user response:

"Traceback" appears to already exist as the traceback is automatic on unhandled exceptions

What you're seeing is the default behavior of sys.excepthook, which is to print a traceback out to stderr anyway, just before the program exits from an unhandled exception.

See for yourself with:

# example.py
import sys
sys.excepthook = lambda *args: None
print("before")
1/0
print("after")

The script above will exit non-zero, but no traceback will be printed since the hook was replaced with a no-op. And "after" will not get printed, because the process will have already exited. So, it is not quite that a traceback is "automatic" on unhandled exceptions, but rather that is the default configuration.

By calling sys.exit(0) you're intentionally suppressing the ZeroDivisionError exception. The interpreter will exit with a zero return code, and as far as the except hook is concerned you have "handled" the ZeroDivisionError and are opting out of the traceback printing (src).

  •  Tags:  
  • Related