Weird generator id() behaviour (was Re: Python code written in 1998, how to improve/change it?)

Carl Cerecke cdc at maxnet.co.nz
Tue Jan 24 15:19:26 EST 2006


Wolfgang Keller wrote:
> On Fri, 20 Jan 2006 05:16:57 +0100, Peter Hansen wrote
> (in article <mailman.821.1137730663.27775.python-list at python.org>):
> 
> 
>>I believe the more modern approach to this is to use generators in some 
>>way, yield each other as the next state.  This way you avoid all almost 
>>all the function call overhead (the part that takes significant time, 
>>which is setting up the stack frame) and don't have to resort to 
>>bytecode hacks for better performance.
> 
> 
> Dumb question from a endless newbie scripting dilettant:
> 
> Do you have a reference to a cookbook example for this method?

It turns out that generators are more efficient than the eval function 
excuting bits of compiled code. About 20-25% faster.

However, the generators exhibit some weird behaviour.

The included code shows an example using a compile/eval FSM method, and 
a generator method. Note, in particular, the pattern of ids of the 
generator objects. I had expected some complications in the ids, but not 
a repeatable sequence of length 3 after the first generator object.

What is going on? Anybody?

#!/usr/bin/env python

import time

s_on = compile('''
print 'on'
action = next_action()
if action == 'lift':
     state = s_on
elif action == 'push':
     state = s_off
else:
     state = None
''','','exec')

s_off = compile('''
print 'off'
action = next_action()
if action == 'lift':
     state = s_on
elif action == 'push':
     state = s_off
else:
     state = None
''','','exec')


def g_on():

     print "on"
     action = next_action()
     if action == 'lift':
         yield g_on()
     elif action == 'push':
         yield g_off()
     else:
         yield None

def g_off():

     print "off"
     action = next_action()
     if action == 'lift':
         yield g_on()
     elif action == 'push':
         yield g_off()
     else:
         yield None


def actions(n):
     import random
     for i in range(n-1):
         yield random.choice(['lift','push'])
     yield None

#r = 1000000
r = 10
next_action = actions(r).next

#a = time.clock()
while next_action():
     pass
#z = time.clock()
#print "action generator:",z-a
next_action = actions(r).next
#print "---"
state = s_on # start state
#a = time.clock()
while state:
     eval(state)
#z = time.clock()
#print z-a
print "---"

next_action =  actions(r).next
s_g_on = g_on()
s_g_off = g_off()
state = s_g_on
#a = time.clock()
while state:
     print id(state)
     state = state.next()
#z = time.clock()
#print z-a


#Cheers,
#Carl.



More information about the Python-list mailing list