Critique of first python code

Zack goldsz at gmail.com
Fri Feb 8 20:30:24 EST 2008


On Feb 8, 4:32 pm, George Sakkis <george.sak... at gmail.com> wrote:
> On Feb 8, 3:40 pm, Arnaud Delobelle <arno... at googlemail.com> wrote:
>
>
>
<snip my original post>
> > How about:
>
> > from itertools import count
> > from random import randrange
>
> > def grow(L, depth, counter=count()):
> >    '''grow L by appending integers and arbitrarily nested lists with a
> >    maximum depth. Returns L.'''
> >    if depth == 0:
> >       return L
> >    else:
> >       L.append(counter.next() if randrange(2) else grow([], depth-1))
> >       return grow(L, depth-1)
>
> Or you may write a more flexible generator version of the above. If
> you're not familiar with generators, think of them as lazy sequences
> that generate successive elements only when needed:
>
> import random
> from itertools import count
>
> def igrow(depth, next=count(1).next, nest=list, random=random.random):
>     '''Generate integers and arbitrarily nested iterables with a
> maximum depth.'''
>     if depth:
>         depth -= 1
>         yield next() if random()<0.5 else
> nest(igrow(depth,next,nest,random))
>         for e in igrow(depth,next,nest,random):
>             yield e
>
> With this you can just as easily generate nested tuples (or other
> containers) instead of lists:
>
>     nested = tuple(igrow(10, nest=tuple))
>
> You may even avoid allocating nested containers altogether:
>
>     from types import GeneratorType
>
>     for x in igrow(10, nest=iter):
>         if isinstance(x, GeneratorType):
>             # process nested generator
>         else:
>             # x is an 'atom'
>
> HTH,
> George

The generators you show here are interesting, and it prodded me on how
to add tuples but at the moment (I'm a python newbie) the generator
seems less readable to me than the alternative. After some input from
Scott David Daniels I changed some of the unnecessary recursion to
while loops. I completely over thought my problem. I've fetched pylint
and I'll be sure to keep it in my toolkit. What does everyone think of
the code below? Are generator functions a more pythonic (preferred?)
way of doing things or will my while loops escape mocking? Thanks for
the feedback this has been a great exercise for me.

import random
from itertools import count

_Val = count(1)

def grow(seq, depth):
    '''
    Grows seq with arbitrarily appended integers, lists and tuples.

    At least depth elements will be added to seq and seq will not grow
    more than depth levels deep.
    Returns seq.

    '''
    while depth > 0:
        choice = random.random()
        if choice < .5:
            seq.append(_Val.next())
        elif choice < .75:
            seq.append(list(grow([], depth-1)))
        else:
            seq.append(tuple(grow([], depth-1)))
        depth -= 1
    return seq


def traverse(seq):
    '''
    Breadth first traversal of seq.

    Prints the non iterable objects of seq in breadth first order.
    Returns the number of atoms (non iterables) in seq.

    '''
    counter = 0
    while seq:
        below = []
        for item in seq:
            if hasattr(item, '__iter__'):
                below.extend(item)
            else:
                print item,
                counter += 1
        #intentional blank line to distinguish long lines that wrap
        print '\n'
        seq = below
    return counter

L = grow([],10)
C = traverse(L)


--
Zack




More information about the Python-list mailing list