How to test a URL request in a "while True" loop

MRAB python at mrabarnett.plus.com
Wed Dec 30 13:46:17 EST 2009


Brian D wrote:
> On Dec 30, 11:06 am, samwyse <samw... at gmail.com> wrote:
>> On Dec 30, 10:00 am, Brian D <brianden... at gmail.com> wrote:
>>
>>> What I don't understand is how to test for a valid URL request, and
>>> then jump out of the "while True" loop to proceed to another line of
>>> code below the loop. There's probably faulty logic in this approach. I
>>> imagine I should wrap the URL request in a function, and perhaps store
>>> the response as a global variable.
>>> This is really more of a basic Python logic question than it is a
>>> urllib2 question.
>> There, I've condensed your question to what you really meant to say.
>> You have several approaches.  First, let's define some useful objects:>>> max_attempts = 5
>>>>> def do_something(i):
>>         assert 2 < i < 5
>>
>> Getting back to original question, if you want to limit the number of
>> attempts, don't use a while, use this:
>>
>>>>> for count in xrange(max_attempts):
>>         print 'attempt', count+1
>>         do_something(count+1)
>>
>> attempt 1
>> Traceback (most recent call last):
>>   File "<pyshell#55>", line 3, in <module>
>>     do_something(count+1)
>>   File "<pyshell#47>", line 2, in do_something
>>     assert 2 < i < 5
>> AssertionError
>>
>> If you want to keep exceptions from ending the loop prematurely, you
>> add this:
>>
>>>>> for count in xrange(max_attempts):
>>         print 'attempt', count+1
>>         try:
>>                 do_something(count+1)
>>         except StandardError:
>>                 pass
>>
>> Note that bare except clauses are *evil* and should be avoided.  Most
>> exceptions derive from StandardError, so trap that if you want to
>> catch errors.  Finally, to stop iterating when the errors cease, do
>> this:
>>
>>>>> try:
>>         for count in xrange(max_attempts):
>>                 print 'attempt', count+1
>>                 try:
>>                         do_something(count+1)
>>                         raise StopIteration
>>                 except StandardError:
>>                         pass
>> except StopIteration:
>>         pass
>>
>> attempt 1
>> attempt 2
>> attempt 3
>>
>> Note that StopIteration doesn't derive from StandardError, because
>> it's not an error, it's a notification.  So, throw it if and when you
>> want to stop iterating.
>>
>> BTW, note that you don't have to wrap your code in a function.
>> do_something could be replaced with it's body and everything would
>> still work.
> 
> I'm totally impressed. I love elegant code. Could you tell I was
> trained as a VB programmer? I think I can still be reformed.
> 
> I appreciate the admonition not to use bare except clauses. I will
> avoid that in the future.
> 
> I've never seen StopIteration used -- and certainly not used in
> combination with a try/except pair. That was an exceptionally valuable
> lesson.
> 
> I think I can take it from here, so I'll just say thank you, Sam, for
> steering me straight -- very nice.

Instead of raising StopIteration you could use 'break':

for count in xrange(max_attempts):
     print 'attempt', count + 1
     try:
         do_something(count + 1)
         break
     except StandardError:
         pass

The advantage, apart from the length, is that you can then add the
'else' clause to the 'for' loop, which will be run if it _didn't_ break
out of the loop. If you break out only after do_something() is
successful, then not breaking out means that do_something() never
succeeded:

for count in xrange(max_attempts):
     print 'attempt', count + 1
     try:
         do_something(count + 1)
         break
     except StandardError:
         pass
else:
     print 'all attempts failed'



More information about the Python-list mailing list