Programming Pearls and Python Fails
Franklin He
604

And that’s why we use generators

Code the access pattern rather than the data.

#! /usr/bin/env python
import random
import logging
import pprint
import time
logger = logging.getLogger(__name__)

def swapIter(thelist, offset, blocklen, rshiftoffset):
for ndex in range(len(thelist)):
if ndex < offset:
yield thelist[ndex]
elif ndex < offset + rshiftoffset:
yield thelist[ndex+blocklen]
elif ndex < offset+blocklen+rshiftoffset:
yield thelist[ndex-rshiftoffset]
else:
yield thelist[ndex]


mylist = [n for n in range(1,20)]

def profile_swapIter():
for i in range(10000):
return swapIter(mylist, range(1,5), range(1,10), range(1,4))

if __name__ == '__main__':
pprint.pprint(mylist)
pprint.pprint([n for n in swapIter(mylist, 5, 10, 2)])

t1 = time.clock()
profile_swapIter()
t2 = time.clock()
print("{}: {} seconds".format("juggle swap", t2-t1))

Result:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[1, 2, 3, 4, 5, 16, 17, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19]
juggle swap: 1.1000000000004062e-05 seconds

This really shines when you need to access things like binary trees:

binary_tree.py

#! /usr/bin/env python
import random
import logging
import pprint
logger = logging.getLogger(__name__)
def btreeRandomIter(pval, smin, smax, depth):
try:
n = 0
for n in range(depth):
yield from btreeRandomIter(smin,
random.randint(1,smin), random.randint(smin, smin**2),
depth-1)
yield from btreeRandomIter(smax,
random.randint(1,smax), random.randint(smax, smax**2),
depth-1)
if not n:
yield smin, (0, 0) #minterm
yield smax, (0, 0) #maxterm
yield pval, (smin, smax)
except:
logger.error('pval: %d, smin: %d, smax: %d, depth: %d' % (pval, smin,
smax, depth))
raise

def btreeRightIterLeafOnly(recs,offset):
if not offset:
offset, (pues, (nada,nothing)) = recs.items().next()
ndex, (lnext, rnext) = recs[offset]
if rnext:
yield from btreeRightIter(recs,rnext)
else:
yield recs[offset]

def btreeLeftIterLeafOnly(recs,offset):
if not offset:
offset, (pues, (nada,nothing)) = recs.items().next()
ndex, (lnext, rnext) = recs[offset]
if lnext:
yield from btreeRightIter(recs,lnext)
else:
yield recs[offset]

def btreeRightIter(recs,offset):
if not offset:
offset, (pues, (nada,nothing)) = recs.items().next()
ndex, (lnext, rnext) = recs[offset]
if rnext:
yield from btreeRightIter(recs,rnext)
yield recs[offset]

def btreeLeftIter(recs,offset):
if not offset:
offset, (pues, (nada,nothing)) = recs.items().next()
ndex, (lnext, rnext) = recs[offset]
if lnext:
yield from btreeRightIter(recs,lnext)
yield recs[offset]

def btreeRightBranchOnly(recs,offset):
if not offset:
offset, (pues, (nada,nothing)) = recs.items().next()
ndex, (lnext, rnext) = recs[offset]
if rnext:
yield from btreeRightIter(recs,rnext)
yield recs[offset]

def btreeLeftBranchOnly(recs,offset):
if not offset:
offset, (pues, (nada,nothing)) = recs.items().next()
ndex, (lnext, rnext) = recs[offset]
if lnext:
yield from btreeRightIter(recs,lnext)
yield recs[offset]

def iterLeavesOnly(recs):
ndex = sorted(recs, key=lambda rec: rec[1][0])
for n in ndex:
if recs[ndex][1][0] == 0:
yield recs[ndex]

def iterBranchOnly(recs):
ndex = sorted(recs, key=lambda rec: rec[1][0],reverse=True)
for n in ndex:
if recs[ndex][1][0] > 0:
yield recs[ndex]

if __name__ == '__main__':
rdict={ val:(val,(lnode,rnode)) for val,(lnode,rnode) in
btreeRandomIter(10,100,1000, 5)}
pprint.pprint(rdict)
print('Index Sorted asc:')
pprint.pprint([rdict[val] for val in sorted(rdict)])
print('Index Sorted desc:')
pprint.pprint([rdict[val] for val in sorted(rdict,reverse=True)])
print('Right Decision from given node.')
pprint.pprint([ndex for ndex,(rval,lval) in btreeRightIter(rdict, 10)])
print('Left decision bottom-up from given node.')
pprint.pprint([ndex for ndex,(rval,lval) in btreeLeftIter(rdict, 10)])
print('Left decision bottom-up from given node.')
pprint.pprint([ndex for ndex,(rval,lval) in btreeLeftIter(rdict, 10)])