How to stop execution of outer function from a inner function? - python

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

Related

getting only the exception ,not the entire stack trace

I want to get only the exception message,not the entire stack trace.A toy example would be as follows:
def div():
try:
print(0/0)
except:
raise Exception('Divide by zero,please check the input!!!')
def func1():
try:
div()
except:
raise Exception('Error in func11 try')
func1()
Expected output
Exception: Divide by zero, please check the input!!!
Exception: Error in func11 try
Any help is highly appreciated.
Below solution worked for me.
import traceback
def div():
try:
print(0/0)
except:
raise Exception('Divide by zero,please check the input!!!')
def func2():
try:
div()
except:
raise Exception('Error in func 2!!!')
def func1():
exceptions=[]
try:
func2()
except Exception as e:
msg=traceback.format_exc()
msg_list= msg.split('\n')
[exceptions.append(line) for line in msg_list if line.startswith('Exception:')]
return exceptions
func1()
output
['Exception: Divide by zero,please check the input!!!',
'Exception: Error in func 2!!!']
If you don't want to get the entire stack trace, you can try this:
def div():
try:
print(0/0)
except Exception as e:
print(e)
The answer of #Kairav Parekh works in your condition and it does not prints the entire stack trace, it only prints the error, which is user-friendly in most cases,
you only need to modify his code to match your requirements and you can put a break statement in except such as below,
def div():
try:
print(0/a)
except Exception as e:
print(e)
break #break here
div()

How to return an object multiple times in Python?

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))

Changing the class of an exception after raising it

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

python stop exception passing

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()

Catch exception and continue try block in Python

Can I return to executing the try block after exception occurs?
For example:
try:
do_smth1()
except:
pass
try:
do_smth2()
except:
pass
vs.
try:
do_smth1()
do_smth2()
except:
??? # magic word to proceed to do_smth2() if there was exception in do_smth1
No, you cannot do that. That's just the way Python has its syntax. Once you exit a try-block because of an exception, there is no way back in.
What about a for-loop though?
funcs = do_smth1, do_smth2
for func in funcs:
try:
func()
except Exception:
pass # or you could use 'continue'
Note however that it is considered a bad practice to have a bare except. You should catch for a specific exception instead. I captured for Exception because that's as good as I can do without knowing what exceptions the methods might throw.
While the other answers and the accepted one are correct and should be followed in real code, just for completeness and humor, you can try the fuckitpy ( https://github.com/ajalt/fuckitpy ) module.
Your code can be changed to the following:
#fuckitpy
def myfunc():
do_smth1()
do_smth2()
Then calling myfunc() would call do_smth2() even if there is an exception in do_smth1())
Note: Please do not try it in any real code, it is blasphemy
You can achieve what you want, but with a different syntax. You can use a "finally" block after the try/except. Doing this way, python will execute the block of code regardless the exception was thrown, or not.
Like this:
try:
do_smth1()
except:
pass
finally:
do_smth2()
But, if you want to execute do_smth2() only if the exception was not thrown, use a "else" block:
try:
do_smth1()
except:
pass
else:
do_smth2()
You can mix them too, in a try/except/else/finally clause.
Have fun!
'continue' is allowed within an 'except' or 'finally' only if the try block is in a loop. 'continue' will cause the next iteration of the loop to start.
So you can try put your two or more functions in a list and use loop to call your function.
Like this:
funcs = [f,g]
for func in funcs:
try: func()
except: continue
For full information you can go to this link
You could iterate through your methods...
for m in [do_smth1, do_smth2]:
try:
m()
except:
pass
one way you could handle this is with a generator. Instead of calling the function, yield it; then whatever is consuming the generator can send the result of calling it back into the generator, or a sentinel if the generator failed: The trampoline that accomplishes the above might look like so:
def consume_exceptions(gen):
action = next(gen)
while True:
try:
result = action()
except Exception:
# if the action fails, send a sentinel
result = None
try:
action = gen.send(result)
except StopIteration:
# if the generator is all used up, result is the return value.
return result
a generator that would be compatible with this would look like this:
def do_smth1():
1 / 0
def do_smth2():
print "YAY"
def do_many_things():
a = yield do_smth1
b = yield do_smth2
yield "Done"
>>> consume_exceptions(do_many_things())
YAY
Note that do_many_things() does not call do_smth*, it just yields them, and consume_exceptions calls them on its behalf
I don't think you want to do this. The correct way to use a try statement in general is as precisely as possible. I think it would be better to do:
try:
do_smth1()
except Stmnh1Exception:
# handle Stmnh1Exception
try:
do_smth2()
except Stmnh2Exception:
# handle Stmnh2Exception
Depending on where and how often you need to do this, you could also write a function that does it for you:
def live_dangerously(fn, *args, **kw):
try:
return fn(*args, **kw)
except Exception:
pass
live_dangerously(do_smth1)
live_dangerously(do_smth2)
But as other answers have noted, having a null except is generally a sign something else is wrong with your code.
This can be done with exec() in a custom function, a list of strings, and a for loop.
The function with exec():
def try_it(string):
try:
exec(string)
print(f'Done: {string}')
except:
print(f'Error. Could not do: {string}')
More on exec():
exec(object)
This function supports dynamic execution of Python code. object must be either a string or a code object.
Example list of strings and for loop:
do_smth_list = ['do_smth1()', 'do_smth2()', 'do_smth3()']
for smth in do_smth_list:
try_it(smth)
This definitely isn't the cleanest way of doing it, but you can put it in a while loop with a variable set to true, and when it runs the function successfully it sets the variable to false, whereas if it fails it keeps the variable set to true.
x = True
while x == True:
try:
do_smth1()
do_smth2()
x = False
except Exception:
x = True
This way what happens is that the while loop will keep on looping the try except section again and again until it works, in which x is set to false and the loop stops
Also, you can implement a break in the while loop instead of basing it on a variable, for example:
while True:
try:
do_smth1()
do_smth2()
break
except Excpetion:
pass
P.S It is good ettiquete to put a specific exception for the except section, instead of leaving it for any exception. It makes the code cleaner and is more sensible when managing errors especially in bigger projects
special_func to avoid try-except repetition:
def special_func(test_case_dict):
final_dict = {}
exception_dict = {}
def try_except_avoider(test_case_dict):
try:
for k,v in test_case_dict.items():
final_dict[k]=eval(v) #If no exception evaluate the function and add it to final_dict
except Exception as e:
exception_dict[k]=e #extract exception
test_case_dict.pop(k)
try_except_avoider(test_case_dict) #recursive function to handle remaining functions
finally: #cleanup
final_dict.update(exception_dict)
return final_dict #combine exception dict and final dict
return try_except_avoider(test_case_dict)
Run code:
def add(a,b):
return (a+b)
def sub(a,b):
return (a-b)
def mul(a,b):
return (a*b)
case = {"AddFunc":"add(8,8)","SubFunc":"sub(p,5)","MulFunc":"mul(9,6)"}
solution = special_func(case)
Output looks like:
{'AddFunc': 16, 'MulFunc': 54, 'SubFunc': NameError("name 'p' is not defined")}
To convert to variables:
locals().update(solution)
Variables would look like:
AddFunc = 16, MulFunc = 54, SubFunc = NameError("name 'p' is not defined")
If do_smth1() worked, then do_smth2() will not be tried.
try:
x=do_smth1()
except:
try:
x=do_smth2()
except:
x="Both Failed"
print (x)

Categories