1

If I have an expression of 1/0, obviously, it gets error:

try:
    1/0
except ZeroDivisionError as err:
    print(err)                      # this prints: division by zero

And the second try, replacing 1/0 by raise ZeroDivisionError...

try:
    raise ZeroDivisionError
except ZeroDivisionError as err:
    print(err)                      # this prints: (nothing)

It prints nothing. Isn't an exception came from raise, same as the a general expression?

Also, how to understand this difference more clearly?

chenghuayang
  • 1,424
  • 1
  • 17
  • 35
  • Here are some [examples](https://stackoverflow.com/questions/2052390/manually-raising-throwing-an-exception-in-python). – Sean Breckenridge Feb 24 '18 at 15:32
  • OK. Thanks. But why it can't catch `raise`? – chenghuayang Feb 24 '18 at 15:44
  • It is catching it, you just didn't tell if to print anything. If you changed `raise ZeroDivisionError` to `raise ZeroDivisionError("ErrorText")`, it would print `"ErrorText"`. It is usually used to describe the error that has been thrown. – Sean Breckenridge Feb 24 '18 at 15:46

1 Answers1

6

All exceptions are a subclass of BaseException, therefore all built-in exceptions should have an args attribute.

args:

The tuple of arguments given to the exception constructor. Some built-in exceptions (like OSError) expect a certain number of arguments and assign a special meaning to the elements of this tuple, while others are usually called only with a single string giving an error message.

The args tuple or string can be provided as the first argument when you raise the exception.

try:
    raise ZeroDivisionError("error")
except ZeroDivisionError as err:
    print(err)  # prints "error"

The err from except Exception as err: is the Exception instance, when you print(err), you're actually calling the __str__ method of the Exception. Most Exception class's __str__ return's args, since it's the default behaviour of BaseException; __str__ will return otherwise if the exception class override BaseException's __str__.

When you raised a plain ZeroDivisionError, you provided no args, and ZeroDivisionError does not have a custom __str__ method, therefore it printed args by default, a.k.a args = None.


As for your question:

Isn't an exception came from raise, same as the a general expression?

Yes. They are the same.

try:
    raise ZeroDivisionError("division by zero")
except ZeroDivisionError as err:
    print(err)       

This will output the same as 1/0.


I went ahead and dig through the source code. // (integer division) and / (true division) have a slightly different error message. But basically they are defined as such:

if (size_b == 0) {
        PyErr_SetString(PyExc_ZeroDivisionError,
                        "division by zero");
        return -1;
    }

Whereas size_b is the divisor. As you can see, 1/0 or any division by zero raises a ZeroDivsionError with args set as "division by zero" or "integer division or modulo by zero" depending how you divide.

Taku
  • 31,927
  • 11
  • 74
  • 85
  • OK. Thanks. This also reminds me of the first time I saw "division by zero" showed. It seems that it‘s the default statement of `ZeroDivisionError`. – chenghuayang Feb 24 '18 at 15:58