问题
My message "Divide by 0 error" is not going through, instead I'm getting a normal ZeroDivisionError
.
#!/usr/bin/python
t = raw_input("do you want to play a game?[y/n]" )
#r = raw_input("Please enter a number")
#e = raw_input("Please enter a number again")
try:
def di (a, b):
return a/b
except ZeroDivisionError:
print "Divide by 0 Error"
while t == "y":
u = raw_input("Please enter / sign ")
if u == "/":
r = int(raw_input("Please enter a number"))
try:
e = int(raw_input("Please enter a number again"))
print "the answer is", di(r, e)
t = raw_input("do you want to play a game?[y/n]" )
except ValueError:
t = raw_input( "Invalid input, must be a number. Press yes to continue, no stop")
回答1:
Look at the code more closely:
try:
def di (a, b):
return a/b
except ZeroDivisionError:
print "Divide by 0 Error"
Your try/except
block includes the entire function definition: it applies specifically to defining the function. There is no exception block active while the function is executing from a call.
Use this instead:
def di (a, b):
try:
return a/b
except ZeroDivisionError:
print "Divide by 0 Error"
回答2:
My take on this question (clearly interesting enough to provoke multiple answers, well done) is to remember that in Python class and function definitions are executed like most other statements.
try:
def di (a, b):
return a/b
except ZeroDivisionError:
print "Divide by 0 Error"
says:
"Attempt to define a function called di
that returns the dividend of its arguments. If defining the function raises a ZeroDivisionError
exception, print an explanatory message." No exception will be raised.
I suspect what is required is instead:
"Define a function that attempts to return the dividend of its arguments. If the division raises a ZeriDivisionError
exception the function prints an explanatory message and returns None
." So the def
should be around the whole function's logic:
def di(a, b):
try:
return a/b
except ZeroDivisionError:
print "Divide by 0 error"
As a more general point of program design, such a function is somewhat badly-coupled. Python programmers would probably conclude, unless constrained by other factors, that it was simpler to leave the exception uncaught: presumably the caller currently has to test for None
to determine whether an exception occurred, so why not just trap the exception wherever it actually has to be handled, and handle it there?
Indicating the invalidity of data by returning an object of a different type makes for complex and hard-to-read code, and is probably best avoided in the long term. Perfectly acceptable for a learning exercise, though!
回答3:
TLDR: Move the exception handler into the function, where the exception actually occurs:
def di(a, b):
try:
return a/b
except ZeroDivisionError:
print("Divide by 0 Error")
Function definitions in Python are executed, and this execution can have side-effects -- such as modifying objects or raising exception. However, on definition only the function signature is run immediately; the body is stored and only run when the function is called.
>>> def func(arg=print("default evaluated")):
... print("body evaluated")
...
default evaluated
>>> func
<function __main__.func(arg=None)>
>>> func()
body evaluated
When you define a function inside an exception handler, this exception handler only receives exceptions raised from evaluating the signature. For example, computing a default argument may raise a ZeroDivisionError
:
>>> def invalid_def(arg=10/0):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
An exception handler for this case is rarely what you want. It can be useful to conditionally define a function, e.g. if a NameError
indicates a dependency is not available.
Commonly you want to handle an exception originating in the body of a function. These are raised whenever the function is actually called:
>>> def invalid_call():
... return 10 / 0
...
>>> invalid_call()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in invalid_call
ZeroDivisionError: division by zero
>>> invalid_call()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in invalid_call
ZeroDivisionError: division by zero
There are two ways to handle such exceptions: externally or internally.
External handling requires an exception handler at each call site. This is more flexible but requires boilerplate, since it requires an exception handler for each call.
>>> try: ... invalid_call() ... except ZeroDivisionError: ... print("suppressed an external error")
Internal handling requires an exception handler in the body. This is less flexible but needs no boilerplate, since one exception handler covers all cases.
>>> def valid_call(): ... try: ... return 10 / 0 ... except ZeroDivisionError: ... print("suppressed an internal error")
Both approaches are valid; which to select depends on whether you rather need usability or re-usability. Notably, it is not uncommon to combine both approaches: an internal handler generalises the exception, and external handler expects only general exceptions.
For example, in your case that would allow to handle multiple operations:
def div(a, b):
try:
return a / b
# convert operation-specific exception to general one
except ZeroDivisionError:
raise ValueError("Cannot divide by 0")
# may be another operation -- add, mul, sub, ...
operation = div
try:
operation(10, 0)
# only handle exception general to all operations
except ValueError as err:
print("Invalid values: %s" % err)
来源:https://stackoverflow.com/questions/58332468/exception-handling-is-ignored-with-try-except-around-a-function-definition