[Tutor] Generator function question?

John Clark clajo04 at mac.com
Sun May 8 20:28:44 CEST 2005


Jacob, 

The "z loop" is in fact just to take time while the screen refreshes with
each output of the status character - as someone else pointed out I could
use a wait() call as well - if I don't put something there to eat up time, I
don't get to display the "spinning wheel" produced by the
sys.stderr.write('\b'+x.next()) line. - All I see displayed is the final
character.  

I think I oversimplified my example here in my first post - my actual code
works on rows of database tables, and the "z loop" is meant to simulate that
work being performed.  The "w loop" is meant to simulate the rows of each
table, and the "y loop" simulates each table.  Your example reduced the
Test1() function into just printing each character of the cycle - given the
simplified code, that reduction is justified, but the spirit of my request
was to preserve each of the loops, and provide a function that when called,
would result in the next character of the cycle being returned without
having to resort to the creation of a global variable ("x" in my example) or
expose to the client code the need to make a .next() call.  Many suggested
that I use a for loop to remove the .next() call, but that would force me to
turn the "y loop" inside out and drive the work being performed based on the
status cycle rather than on the collection of rows of the table.  This I
think results in real-world code that is harder to understand (although in
the simplified example there is no real difference)

I first thought a generator function was the appropriate way to implement
and expose this status cycle, but through the evolution of this thread, I
think that a generator function isn't appropriate in this case (although a
generator function is one way that the exposed function could use to select
the next character in the sequence).

At this point with help from others on this list, I have refined the
function to the following alternatives:

def neverEndingStatus():
     try: 
          neverEndingStatus.index = (neverEndingStatus.index + 1) % 4
     except AttributeError:
          neverEndingStatus.index = 0
          neverEndingStatus.chars = r'|\-/'
     
     return neverEndingStatus.chars[neverEndingStatus.index]

- or - 

import itertools

def neverEndingStatus():
     try: 
          neverEndingStatus.cycle
     except AttributeError:
          neverEndingStatus.cycle = itertools.cycle(r'|\-/')
     return neverEndingStatus.cycle.next()


The main (philosophical) problem I have with these is that they both use the
EAFP approach to function attributes - I am much more of a LBYL person - but
I have not seen a LBYL implementation of function attributes.

I hope this explains a bit of what should have been explained in the first
post...

-jdc




On 5/8/05 2:02 PM, "Jacob S." <keridee at jayco.net> wrote:

>> import sys
>> 
>> def neverEndingStatus(currentChar_ = '|'):
>>    while 1:
>>        if currentChar_ == '|':
>>            currentChar_ = '\\'
>>        elif currentChar_ == '\\':
>>            currentChar_ = '-'
>>        elif currentChar_ == '-':
>>            currentChar_ = '/'
>>        elif currentChar_ == '/':
>>            currentChar_ = '|'
>>        yield currentChar_
>> 
>> 
>> x = neverEndingStatus()
>> 
>> def Test1():
>>    for w in range(1, 100):
>>        sys.stderr.write('\b'+x.next())
> 
> ########################################
>>        for z in range(1, 10000):
>>            z = z + 1
> 
> What on earth is the point of this? Why put a loop in there that does
> nothing?
> Are you just trying to take time?
> ########################################
> 
>> def Test2():
>>    for y in range(1, 10):
>>        sys.stderr.write('\b \nTesting'+str(y)+'\t')
>>        Test1()
>> 
>> Test2()
> 
> import sys
> from itertools import cycle
> 
> # nesl = Never ending status list
> nesl = ["|","\\","-","/"]
> 
> a = cycle(nesl)
> 
> ## ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ##
> ## | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
> | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ##
> ## This is just using itertools' cycle to automatically make the iterator
> you were trying for ##
> 
> # Now we rewrite your test cases
> 
> def Test1():
>     sys.stderr.write("\b"+"\b".join(a.next() for x in range(1,100)))
>     ## You realize that this will only give you 99 characters, not 100
> 
> def Test2():
>     for i in range(1,10):  ## You realize again that this only runs 9
> times...
>         sys.stderr.write("\b \nTesting %s\t" % y)
>         Test1()
> 
> Test2()
> 
> 
> Well, this is not tested, but it shows that you can use itertools.cycle to
> do what you want.
> 
> Also, the test cases are slightly neater (to me) too.
> 
> Okay, I'm done
> Jacob 
> 




More information about the Tutor mailing list