Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

More elegant way to try running a function X times?

0 views
Skip to first unread message

Gilles Ganault

unread,
Nov 19, 2008, 9:09:30 AM11/19/08
to
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.

Tim Chase

unread,
Nov 19, 2008, 9:23:12 AM11/19/08
to pytho...@python.org
> 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

.

Sion Arrowsmith

unread,
Nov 19, 2008, 9:37:06 AM11/19/08
to

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".

--
\S -- si...@chiark.greenend.org.uk -- http://www.chaos.org.uk/~sion/
"Frankly I have no feelings towards penguins one way or the other"
-- Arthur C. Clarke
her nu becomeþ se bera eadward ofdun hlæddre heafdes bæce bump bump bump

Nicholas Ferenc Fabry

unread,
Nov 19, 2008, 9:31:48 AM11/19/08
to Gilles Ganault, pytho...@python.org

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


> Thank you.
> --
> http://mail.python.org/mailman/listinfo/python-list

Gilles Ganault

unread,
Nov 19, 2008, 10:21:23 AM11/19/08
to
On 19 Nov 2008 14:37:06 +0000 (GMT), Sion Arrowsmith

<si...@chiark.greenend.org.uk> wrote:
>Note very carefully that the "else" goes with the "for" and not the "if".

Thanks guys.

George Sakkis

unread,
Nov 19, 2008, 11:05:31 AM11/19/08
to

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

Boris Borcic

unread,
Nov 20, 2008, 12:45:33 PM11/20/08
to pytho...@python.org
Tim Chase wrote:

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

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

Tim Chase

unread,
Nov 20, 2008, 1:13:21 PM11/20/08
to Boris Borcic, pytho...@python.org
>>> 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()
>
> 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

Steve Holden

unread,
Nov 20, 2008, 1:28:07 PM11/20/08
to pytho...@python.org

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
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

Boris Borcic

unread,
Nov 20, 2008, 4:18:36 PM11/20/08
to pytho...@python.org
Tim Chase wrote:
>>>> 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()
>>
>> 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.

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

0 new messages