How to limit the number of failed attempts to call a function? - python

How rewrite this code in a pythonic way?
tried = 0
while tried < 3:
try:
function()
break
except Exception as e:
print e
tried += 1
Is there a built-in function I could use?

A more pythonic way to do something N times is to use xrange with the _ variable:
for _ in xrange(3):
try:
function()
break
except Exception as e:
print e
Also, consider catching a more specific exception instead of the root Exception class.

You can use a retry decorator:
#retries(3)
def execTask():
f()
One simpler than the one in the provided link could look like this:
def retry(times=3):
def do_retry(f, *args, **kwargs):
cnt = 0
while cnt < times:
try:
f(*args, **kwargs)
return
except:
cnt += 1
return do_retry
And could be used like this:
#retry(3)
def test():
print("Calling function")
raise Exception("Some exception")

tried = 0
while tried < 3:
try:
function()
break
except Exception as e:
print e
tried += 1
It's almost exactly how you wrote it, except you need a colon at the end of your while line and move the break to the "try" block.

Motivation
Given the motivation of the OP was to limit the number of failing attempt to run a function(), the following code does not provide any artificial gymnastics, but both limits the number of tries and retains the actual number of attempts for ex-post analyses ( if needed down the road )
tried = 0
while tried < 3:
try:
function() # may throw an Exception
break # on success pass through/return from function()
except Exception as e:
print e
tried += 1
# retains a value of tried for ex-post review(s) if needed

Related

How write smart twice the "same blocks with if and return" in a function?

[Follow up]
Make them strings and exec them may be work.
I'm trying. -> It doesn't work because of "await" problem. life is not simple...
I am writing an function like this.
def func():
[do something]
<here>
a = getA()
if a > 0:
return("abnormal exit1")
</here>
[do something another]
<here>
a = getA()
if a > 0:
return("abnormal exit2")
</here>
return("normal exit")
I need to write just same judgement twice because of network lag.
But I feel that writing them twice flatly isn't smart.
Is there any right way to squeeze them out like a preprocessor or a macro?
I want to Put them together out with "if and return".
It doesn't really look like there's much being repeated that doesn't need to be repeated. The only "bloat" here is the call to getA (which has to be repeated) and the check of its return value, which you can combine into a single line:
if (a := getA()) > 0:
Then you can write
def func():
# Stuff before first call
if (a := getA()) > 0:
return("abnormal exit1")
# Stuff before second call
if (a := getA()) > 0:
return("abnormal exit2")
return("normal exit")
Use a loop with the amount of tries to allow:
n = 2
def func():
for i in range(n)
# do something
a = getA()
if a > 0:
return(f"abnormal exit{i+1}")
return("normal exit")
If it's just a couple lines including a simple if, I wouldn't bother packing it into another function.
However, if you really wanted to, you could raise an exception in an inner function and catch that exception and return "abnormal exit", or return "normal exit" if the exception isn't caught.
class CustomError(Exception):
pass
def func():
def inner_func(msg):
a = getA()
if a > 0:
raise CustomError(msg)
try:
# [ do something]
inner_func("abnormal exit 1")
# [ do something]
inner_func("abnormal exit 2")
except CustomError as e:
return e.args[0]
return "normal exit"

How to set a standard exception handler for multiple functions

Let's say I have three functions that do different things but should react to a set of exceptions in the same way. One of them might look like:
def get_order_stat(self, Order_id):
status_returned = False
error_count = 0
while status_returned == False:
try:
stat_get = client.queryOrder(orderId=Order_id)
except MalformedRequest:
print('Order ID not yet findable, keep trying')
error_count += 1
time.sleep(int(1))
except InternalError:
print('Order check returned InternalError, keep trying')
error_count += 1
time.sleep(int(1))
except StatusUnknown:
print('Order check returned StatusUnknown, keep trying')
error_count += 1
time.sleep(int(1))
else:
status = stat_get['status']
status_returned = True
finally:
if error_count >= 10:
print('Error loop, give up')
break
return status
The vast majority of the code is the exception handling, and I'd like to avoid having to repeat it in every function that needs it. Is there a way to define something like an exception handling function containing the handling code? Ideally my function would end up effectively:
def get_order_stat(self, Order_id):
status_returned = False
while status_returned == False:
try:
stat_get = client.queryOrder(orderId=Order_id)
except:
handler_function()
else:
status = stat_get['status']
status_returned = True
return status
You practically already did it. Just define the handler_function() somewhere and it gets called when an Exception in the try block gets raised.
Maybe helpful: you can bind the Exception to a variable and use it for exception handling in the handler function:
except Exception as e:
handler_function(e)
Then you can for example do `print(e)̀ to give out the exception or do different handling for different exceptions in the function. Hope that helps!
You also can specify several exceptions in one line if you don't want to be general, but catch all specific exceptions with one statement:
except (ExceptionType1, ExceptionType2, ExceptionType3) as e:
handler_function(e)
I might write a decorator function for the exception handling; for instance using functool.wraps.
from functool import wraps
def retry(f):
#wraps(f)
def wrapper(*args, **kwargs):
error_count = 0
while error_count < 10:
try:
return f(*args, **kwargs)
except MalformedRequest:
print('Order ID not yet findable, keep trying')
except InternalError:
print('Order check returned InternalError, keep trying')
error_count += 1
time.sleep(int(1))
print('Error loop, give up')
return None
return wrapper
Then you can write a very simple API call function, and wrap it with the retry wrapper:
#retry
def get_order(order_id):
stat_get = client.queryOrder(orderId=order_id)
return stat_get['status']
In your original function, notice that you can move the contents of the try...else block into the main try block without affecting the logic (extracting the value from the query result won't raise one of the network-related exceptions), and then you can just return out of the try block instead of arranging to stop the loop. Then the contents of the try block are what I've broken out here into get_order(). I restructured the remaining loop a little and turned it into decorator form.

Python try/except depending on variable

i need continue in program after except when variable is True but when variable is False need exit program.
I think there will be if else but I'm not sure how to use it.
for examlpe:
var = True
try:
print 2/0
except:
exit(1)
... continue executing
var = False
try:
print 2/0
except:
exit(1)
... exit
Thanks for comments.
This ought to do the trick, by the way you should probably use raise.
var = True
try:
print 2/0
except:
if not var:
# I recommend using raise, as it would show you the error
exit(1)
If you have a number of except groups which will need to use the var try this
Note that you can expand myexcept using decorators or closures in order to set up additional processing within the exception as well. Since a function is an object, you can use a different specialfunc() for every except: that you write. You can set up the myexcept to handle calls to specialfunc() with arguments as well using the variable arguments process as shown below
def specialfunc1():
# put the special function code here
def specialfunc2(arg1):
# put the processing here
def specialfunc3(arg1, arg2):
# put the processing here
def myexcept(var, e, specialfunc, *args)
print 'Exception caught for ', e
if var:
specialfunc(*args)
else:
raise # This raises the current exception to force an exit
try:
# code you are testing
2/0
except Error1, e:
myexcept(var, e, specialfunc1)
except Error2, e:
myexcept(var, e, specialfunc2(arg1))
except Error3, e:
myexcept(var, e, specialfunc3(arg1, arg2))
except: # this default forces the regular exception handler
# remaining code

Multiple try codes in one block

I have a problem with my code in the try block.
To make it easy this is my code:
try:
code a
code b #if b fails, it should ignore, and go to c.
code c #if c fails, go to d
code d
except:
pass
Is something like this possible?
You'll have to make this separate try blocks:
try:
code a
except ExplicitException:
pass
try:
code b
except ExplicitException:
try:
code c
except ExplicitException:
try:
code d
except ExplicitException:
pass
This assumes you want to run code c only if code b failed.
If you need to run code c regardless, you need to put the try blocks one after the other:
try:
code a
except ExplicitException:
pass
try:
code b
except ExplicitException:
pass
try:
code c
except ExplicitException:
pass
try:
code d
except ExplicitException:
pass
I'm using except ExplicitException here because it is never a good practice to blindly ignore all exceptions. You'll be ignoring MemoryError, KeyboardInterrupt and SystemExit as well otherwise, which you normally do not want to ignore or intercept without some kind of re-raise or conscious reason for handling those.
You can use fuckit module.
Wrap your code in a function with #fuckit decorator:
#fuckit
def func():
code a
code b #if b fails, it should ignore, and go to c.
code c #if c fails, go to d
code d
Extract (refactor) your statements. And use the magic of and and or to decide when to short-circuit.
def a():
try: # a code
except: pass # or raise
else: return True
def b():
try: # b code
except: pass # or raise
else: return True
def c():
try: # c code
except: pass # or raise
else: return True
def d():
try: # d code
except: pass # or raise
else: return True
def main():
try:
a() and b() or c() or d()
except:
pass
If you don't want to chain (a huge number of) try-except clauses, you may try your codes in a loop and break upon 1st success.
Example with codes which can be put into functions:
for code in (
lambda: a / b,
lambda: a / (b + 1),
lambda: a / (b + 2),
):
try: print(code())
except Exception as ev: continue
break
else:
print("it failed: %s" % ev)
Example with arbitrary codes (statements) directly in the current scope:
for i in 2, 1, 0:
try:
if i == 2: print(a / b)
elif i == 1: print(a / (b + 1))
elif i == 0: print(a / (b + 2))
break
except Exception as ev:
if i:
continue
print("it failed: %s" % ev)
Lets say each code is a function and its already written then the following can be used to iter through your coding list and exit the for-loop when a function is executed without error using the "break".
def a(): code a
def b(): code b
def c(): code c
def d(): code d
for func in [a, b, c, d]: # change list order to change execution order.
try:
func()
break
except Exception as err:
print (err)
continue
I used "Exception " here so you can see any error printed. Turn-off the print if you know what to expect and you're not caring (e.g. in case the code returns two or three list items (i,j = msg.split('.')).
You could try a for loop
for func,args,kwargs in zip([a,b,c,d],
[args_a,args_b,args_c,args_d],
[kw_a,kw_b,kw_c,kw_d]):
try:
func(*args, **kwargs)
break
except:
pass
This way you can loop as many functions as you want without making the code look ugly
I use a different way, with a new variable:
continue_execution = True
try:
command1
continue_execution = False
except:
pass
if continue_execution:
try:
command2
except:
command3
to add more commands you just have to add more expressions like this:
try:
commandn
continue_execution = False
except:
pass
I ran into this problem, but then it was doing the things in a loop which turned it into a simple case of issueing the continue command if successful. I think one could reuse that technique if not in a loop, at least in some cases:
while True:
try:
code_a
break
except:
pass
try:
code_b
break
except:
pass
etc
raise NothingSuccessfulError
Like Elazar suggested:
"I think a decorator would fit here."
# decorator
def test(func):
def inner(*args, **kwargs):
try:
func(*args, **kwargs)
except: pass
return inner
# code blocks as functions
#test
def code_a(x):
print(1/x)
#test
def code_b(x):
print(1/x)
#test
def code_c(x):
print(1/x)
#test
def code_d(x):
print(1/x)
# call functions
code_a(0)
code_b(1)
code_c(0)
code_c(4)
output:
1.0
0.25

How to write multiple try statements in one block in python?

I want to do:
try:
do()
except:
do2()
except:
do3()
except:
do4()
If do() fails, execute do2(), if do2() fails too, exceute do3() and so on.
best Regards
If you really don't care about the exceptions, you could loop over cases until you succeed:
for fn in (do, do2, do3, do4):
try:
fn()
break
except:
continue
This at least avoids having to indent once for every case. If the different functions need different arguments you can use functools.partial to 'prime' them before the loop.
I'd write a quick wrapper function first() for this.
usage: value = first([f1, f2, f3, ..., fn], default='All failed')
#!/usr/bin/env
def first(flist, default=None):
""" Try each function in `flist` until one does not throw an exception, and
return the return value of that function. If all functions throw exceptions,
return `default`
Args:
flist - list of functions to try
default - value to return if all functions fail
Returns:
return value of first function that does not throw exception, or
`default` if all throw exceptions.
TODO: Also accept a list of (f, (exceptions)) tuples, where f is the
function as above and (exceptions) is a tuple of exceptions that f should
expect. This allows you to still re-raise unexpected exceptions.
"""
for f in flist:
try:
return f()
except:
continue
else:
return default
# Testing.
def f():
raise TypeError
def g():
raise IndexError
def h():
return 1
# We skip two exception-throwing functions and return value of the last.
assert first([f, g, h]) == 1
assert first([f, g, f], default='monty') == 'monty'
It seems like a really odd thing to want to do, but I would probably loop over the functions and break out when there were no exception raised:
for func in [do, do2, do3]:
try:
func()
except Exception:
pass
else:
break
Here is the simplest way I found, just embed the try under the previous except.
try:
do()
except:
try:
do2()
except:
do3()
You should specify the type of the exception you are trying to catch each time.
try:
do()
except TypeError: #for example first one - TypeError
do_2()
except KeyError: #for example second one - KeyError
do_3()
and so on.
if you want multiple try statments you can do it like this, including the except statement. Extract (refactor) your statements. And use the magic of and and or to decide when to short-circuit.
def a():
try: # a code
except: pass # or raise
else: return True
def b():
try: # b code
except: pass # or raise
else: return True
def c():
try: # c code
except: pass # or raise
else: return True
def d():
try: # d code
except: pass # or raise
else: return True
def main():
try:
a() and b() or c() or d()
except:
pass
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise

Categories

Resources