I wrote the following code, which raises an exception, while a thread continuously changes the class of the raised exception:
import threading
import time
class Foo(Exception):
pass
class Bar(Exception):
pass
class MyExc(Exception):
pass
b = True
e = MyExc()
def mess():
global e
global b
time.sleep(0.00000000000000000000001)
while b:
e.__class__ = Bar
e.__class__ = Foo
threading.Thread(target=mess).start()
try:
try:
try:
try:
try:
raise e
except Foo:
print(1)
except Foo:
print(2)
except Foo:
print(3)
except Foo:
print(4)
except Foo:
print(5)
except Bar:
print('bar')
except MyExc:
print('myexc')
b = False
With CPython, different timings make it print either 1, bar, or myexc (you may have to tweak the sleep time a bit to get either three of them). But never an other number.
Why? Is it because CPython does not run other threads while unwinding the stack?
I suspect what is happening is that when you start your thread, it is changing the type of 'e' before it gets to the raise command. Once it gets to the raise command, the exception is captured at it's current type, which will either be MyExc, Foo, or Bar, and then moves through the exception handling logic.
If you want to play with it more, you can reraise the exception inside the try/except logic. Something like:
try:
try:
try:
raise e
except:
print(1)
raise
except:
print(2)
raise
except:
print(3)
raise
Related
Here is what I want to do:
def bfunc():
try:
do_someting
except Exception as e:
return
def afunc():
bfunc()
xxx
def cfunc():
xxx
def main():
afunc()
cfunc()
in bfunc(),I catch the exception.Now in my main(), I want to stop the afunc() execution when an exception occurs but proceed to execute cfunc().
How can I do this or is there any other way to catch the exception without too many nested try statements?
Tx
Because bfunc() is a function, therefore, to stop the execution of bfunc you can simply use return to stop bfunc. This won't affect cfunc because return only affect bfunc.
def bfunc():
try:
# do_someting
except Exception as e:
return # Exit the bfunc() immediately
You can use below code to see whether print will work or not
def bfunc():
try:
raise IndexError
except Exception as e:
return
def main():
bfunc()
print("Hello world")
if __name__ == "__main__":
main()
Just move the try exception block to afunc. It should give the effect you want.
def bfunc():
do_someting
def afunc():
try:
bfunc()
except Exception as e:
return
xxx #you can move it to try block in order to catch exceptions here too, but I don't know if it's what you like to do
In the following example I would like to be able to call the function b() from a(), and for a() to recognize that an IndexError has occurred in b().
def a():
try:
b()
except IndexError:
print('Caught the error in a!')
def b():
array = ["First", "Second"]
try:
print(array[2])
except IndexError:
print('Caught the error in b!')
a()
The output of this script looks like this:
Caught the error in b!
What I would like to see is a way for this script to output the following:
Caught the error in b!
Caught the error in a!
I would greatly prefer an answer with the constraint that modifications only be made to the function a() for the specific real-world scenario I'm actually dealing with, but will accept another answer if this isn't possible.
My (incorrect) intuition would assume that the script is simply terminating after the exception is being caught in b(), but the following example proves that this is not the case:
def a():
try:
b()
except IndexError:
print('Caught the error in a!')
print('Both chances are over now.')
def b():
array = ["First", "Second"]
try:
print(array[2])
except IndexError:
print('Caught the error in b!')
a()
This script will output the following:
Caught the error in b!
Both chances are over now.
Which proves to me that the function a() will continue executing after the IndexError exception occurs in b().
def a():
try:
b()
except IndexError:
print('Caught the error in a!')
print('Both chances are over now.')
def b():
array = ["First", "Second"]
try:
print(array[2])
except IndexError:
print('Caught the error in b!')
raise
a()
Use <exception> as e and raise <exception> from e:
def a():
try:
b()
except IndexError:
print('Caught the error in a!')
print('Both chances are over now.')
def b():
array = ["First", "Second"]
try:
print(array[2])
except IndexError as e:
raise IndexError('Caught the error in b!') from e
I have a problem when doing an exception handling in a Python class.
My class structure is like:
class base():
def func():
try:
# some codes to deal with requests headers in here
requests.get('...', timeout=0.1)
return something
except:
# So when timeout in request occurs, func() will return 'Error'
return 'Error'
def A():
func()
def B():
func()
# there are about 10 functions that have called func().
def index():
reply = A()
reply = B()
# and A() B() functions are called here.
return reply
My question is, is there a way to return an 'Error' to index function directly, instead of doing exception handling every time when calling it? That is, change func() only, and it has to return 2 times(func() -> A() -> index()), so reply in index function will be 'Error'.
def test(a = 1):
try:
if a:
raise Exception
else:
return a+10
except:
return "error"
You can try something like this:
def func():
try:
# the area may raise excetion
pass
except Exception1:
# anything you like
return 'error'
except Exception2:
# anything you like
return 'error'
Using requests.Timeout
def func():
try:
# some codes to deal with requests headers in here
rq = requests.get('...', timeout=0.1)
return 'something'
except requests.Timeout as err:
# So when timeout in request occurs, func() will return 'Error'
return ('Error {}'.format(err))
I have a custom InvalidError, and I want my function handles two kinds of errors: one is InvalidError, the other are all other errors. I tried in this way:
try:
a = someFunc()
if a:
# do things
else:
raise InvalidError('Invalid Error!')
except InvalidError as e:
return "Invalid"
except Exception as ex:
return "Other"
But seems I will get Other either way. How can I achieve my functionality in right way?
Can you tell us how you created you InvalidError class? It is working.
class InvalidError(Exception):
pass
>>> try:
... raise InvalidError("dsfsdf")
... except InvalidError as my_exception:
... print "yes"
... except Exception as e:
... print "No"
...
yes
One way of doing this would be to create a context manager class. Within the contect manager you can ignore whatever error you like,
E.g.
class ctx_mgr:
def __enter__(self):
cm = object()
return cm
def __exit__(self, exc_type, exc_value, exc_tb):
return (exc_type == InvalidError)
with ctx_mgr:
a = someFunc()
How can I get the name of an exception that was raised in Python?
e.g.,
try:
foo = bar
except Exception as exception:
name_of_exception = ???
assert name_of_exception == 'NameError'
print "Failed with exception [%s]" % name_of_exception
For example, I am catching multiple (or all) exceptions, and want to print the name of the exception in an error message.
Here are a few different ways to get the name of the class of the exception:
type(exception).__name__
exception.__class__.__name__
exception.__class__.__qualname__
e.g.,
try:
foo = bar
except Exception as exception:
assert type(exception).__name__ == 'NameError'
assert exception.__class__.__name__ == 'NameError'
assert exception.__class__.__qualname__ == 'NameError'
If you want the fully qualified class name (e.g. sqlalchemy.exc.IntegrityError instead of just IntegrityError), you can use the function below, which I took from MB's awesome answer to another question (I just renamed some variables to suit my tastes):
def get_full_class_name(obj):
module = obj.__class__.__module__
if module is None or module == str.__class__.__module__:
return obj.__class__.__name__
return module + '.' + obj.__class__.__name__
Example:
try:
# <do something with sqlalchemy that angers the database>
except sqlalchemy.exc.SQLAlchemyError as e:
print(get_full_class_name(e))
# sqlalchemy.exc.IntegrityError
You can print the exception using some formated strings:
Example:
try:
#Code to execute
except Exception as err:
print(f"{type(err).__name__} was raised: {err}")
You can also use sys.exc_info(). exc_info() returns 3 values: type, value, traceback. On documentation: https://docs.python.org/3/library/sys.html#sys.exc_info
import sys
try:
foo = bar
except Exception:
exc_type, value, traceback = sys.exc_info()
assert exc_type.__name__ == 'NameError'
print "Failed with exception [%s]" % exc_type.__name__
This works, but it seems like there must be an easier, more direct way?
try:
foo = bar
except Exception as exception:
assert repr(exception) == '''NameError("name 'bar' is not defined",)'''
name = repr(exception).split('(')[0]
assert name == 'NameError'
The other answers here are great for exploration purposes, but if the primary goal is to log the exception (including the name of the exception), perhaps consider using logging.exception instead of print?