More elegant way to try running a function X times?

G

Gilles Ganault

Hello

As a newbie, it's pretty likely that there's a smarter way to do this,
so I'd like to check with the experts:

I need to try calling a function 5 times. If successful, move on; If
not, print an error message, and exit the program:

=====
success = None

for i in range(5):
#Try to fetch public IP
success = CheckIP()
if success:
break

if not success:
print "Exiting."
sys.exit()
=====

Thank you.
 
T

Tim Chase

I need to try calling a function 5 times. If successful, move on; If
not, print an error message, and exit the program:

success = None
for i in range(5):
#Try to fetch public IP
success = CheckIP()
if success:
break
if not success:
print "Exiting."
sys.exit()

Though a bit of an abuse, you can use

if not any(CheckIP() for _ in range(5)):
print "Exiting"
sys.exit()

(this assumes Python2.5, but the any() function is easily
recreated per the docs at [1]; and also assumes the generator
creation of 2.4, so this isn't as useful in 2.3 and below)

Alternatively, you can use the for/else structure:

for i in range(5):
if CheckIP():
break
else:
print "Exiting"
sys.exit()

-tkc

[1]
http://www.python.org/doc/2.5.2/lib/built-in-funcs.html#l2h-10





..
 
N

Nicholas Ferenc Fabry

Hello

As a newbie, it's pretty likely that there's a smarter way to do this,
so I'd like to check with the experts:

I need to try calling a function 5 times. If successful, move on; If
not, print an error message, and exit the program:

=====
success = None

for i in range(5):
#Try to fetch public IP
success = CheckIP()
if success:
break

if not success:
print "Exiting."
sys.exit()
=====

A little simpler:

for i in range(5):
if CheckIP():
break
else:
print "Exiting."
sys.exit()

The else part will only fire if the for finishes without breaking.
Hope this helps a bit...


Nick Fabry
 
S

Sion Arrowsmith

Gilles Ganault said:
As a newbie, it's pretty likely that there's a smarter way to do this,
so I'd like to check with the experts:

I need to try calling a function 5 times. If successful, move on; If
not, print an error message, and exit the program:

=====
success = None

for i in range(5):
#Try to fetch public IP
success = CheckIP()
if success:
break

if not success:
print "Exiting."
sys.exit()
=====

for i in range(5):
if CheckIP():
break
else:
print "Exiting."
sys.exit()

Note very carefully that the "else" goes with the "for" and not the "if".
 
G

George Sakkis

Thanks guys.

And if you end up doing this for several different functions, you can
factor it out with the following decorator:

class MaxRetriesExceededError(Exception):
pass

def retry(n):
def decorator(f):
def wrapper(*args, **kwds):
for i in xrange(n):
r = f(*args, **kwds)
if r: return r
raise MaxRetriesExceededError
return wrapper
return decorator

If the number of retries is fixed and known at "compile" time, you can
use the standard decorator syntax:

@retry(5)
def CheckIP():
...

If not, just decorate it explicitly at runtime:

def CheckIP():
...

n = int(raw_input('Give number of retries:'))
CheckIP = retry(n)(CheckIP)


HTH,
George
 
B

Boris Borcic

Tim said:
Though a bit of an abuse, you can use

if not any(CheckIP() for _ in range(5)):
print "Exiting"
sys.exit()

I don't see why you speak of abuse, bit of abuse would be, say if you replaced
range(5) by '12345' to win a char; but otoh I think you misspelled any() for all().

Cheers BB
 
T

Tim Chase

success = None
I don't see why you speak of abuse, bit of abuse would be, say if you replaced
range(5) by '12345' to win a char; but otoh I think you misspelled any() for all().

The OP's code break'ed (broke?) upon the first success, rather
than checking all of them. Thus, it would be any() rather than
all(). Using all() would require 5 successful calls to
CheckIP(), rather than one-out-of-five successful calls.

As for abuse, the "for _ in iterable" always feels a little hokey
to me. It works, but feels warty.

-tkc
 
S

Steve Holden

Gilles said:
Hello

As a newbie, it's pretty likely that there's a smarter way to do this,
so I'd like to check with the experts:

I need to try calling a function 5 times. If successful, move on; If
not, print an error message, and exit the program:

=====
success = None

for i in range(5):
#Try to fetch public IP
success = CheckIP()
if success:
break

if not success:
print "Exiting."
sys.exit()

Use the for statement's "else" clause: it's there to allow you to
specify code to be executed only when the loop terminates normally.

for i in range(5):
if CheckIP():
break
else:
sys.exit("Could not verify IP address")
.... remainder of program ...

regards
Steve
 
B

Boris Borcic

Tim said:
The OP's code break'ed (broke?) upon the first success, rather than
checking all of them. Thus, it would be any() rather than all(). Using
all() would require 5 successful calls to CheckIP(), rather than
one-out-of-five successful calls.

Right. So it could also be written " if all(not CheckIP()... ". Perhaps more
closely re-telling the OP's ?
As for abuse, the "for _ in iterable" always feels a little hokey to
me. It works, but feels warty.

I guess this means you did not learn Prolog before Python ?

Cheers, BB
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top