Velocity Reviews > Critique of first python code

# Critique of first python code

Zack
Guest
Posts: n/a

 02-08-2008
Hi all. I'm just starting to pick up python. I wanted to play with nested
lists so first I wrote a little bit of code to create arbitrarily nested
lists (grow). Then I wrote a breadth first search. I'm putting this small
snippet up asking for criticism. Was there a more elegant way to do what I'm
doing? Anything that goes against convention? Anything that fingers me as a
c++ programmer? Are there standard modules that do these kind of things?
Thanks for any feedback.

##############################
from random import randint

Val = 0

def grow(L,depth):
'''grows L by appending integers and arbitrarily nested lists with a
maximum
depth. Returns L.'''
global Val
if depth == 0:
return L
else:
choice = randint(1,2)
if 1 == choice:
Val += 1
L.append(Val)
return grow(L,depth-1)
elif 2 == choice:
L.append( grow([],depth-1) )
return grow(L,depth-1)

def traverse(L, count=0):
'''Prints the non iterable object of L in breadth first order.
Returns count + the number of non iterables in L.'''
if L == []:
return count
n = []
for e in L:
if not hasattr(e,'__iter__'):
print e,
count += 1
else:
n[:] += e
print '\n'
return traverse(n,count)

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

--
Zack

Arnaud Delobelle
Guest
Posts: n/a

 02-08-2008
On Feb 8, 7:20*pm, "Zack" <(E-Mail Removed)> wrote:
> Hi all. I'm just starting to pick up python. I wanted to play with nested
> lists so first I wrote a little bit of code to create arbitrarily nested
> lists (grow). Then I wrote a breadth first search. *I'm putting this small
> snippet up asking for criticism. Was there a more elegant way to do what I'm
> doing? Anything that goes against convention? *Anything that fingers me as a
> c++ programmer? Are there standard modules that do these kind of things?
> Thanks for any feedback.
>
> ##############################
> from random import randint
>
> Val = 0
>
> def grow(L,depth):
> * *'''grows L by appending integers and arbitrarily nested lists with a
> maximum
> * *depth. Returns L.'''
> * *global Val
> * *if depth == 0:
> * * * return L
> * *else:
> * * * choice = randint(1,2)
> * * * if 1 == choice:
> * * * * *# add a numerical literal
> * * * * *Val += 1
> * * * * *L.append(Val)
> * * * * *return grow(L,depth-1)
> * * * elif 2 == choice:
> * * * * *# add a list
> * * * * *L.append( grow([],depth-1) )
> * * * * *return grow(L,depth-1)

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)

> def traverse(L, count=0):
> * *'''Prints the non iterable object of L in breadth first order.
> * *Returns count + the number of non iterables in L.'''
> * *if L == []:
> * * * return count
> * *n = []
> * *for e in L:
> * * * if not hasattr(e,'__iter__'):
> * * * * *print e,
> * * * * *count += 1
> * * * else:
> * * * * *n[:] += e

I would write n.extend(e) here (or n += e)
> * *print '\n'
> * *return traverse(n,count)
>
> L = grow([],10)
> C = traverse(L)
> ##############################
>
> --
> Zack

--
Arnaud

Tomek Paczkowski
Guest
Posts: n/a

 02-08-2008
Zack wrote:

> Hi all. I'm just starting to pick up python. I wanted to play with nested
> lists so first I wrote a little bit of code to create arbitrarily nested
> lists (grow). Then I wrote a breadth first search. I'm putting this small
> snippet up asking for criticism. Was there a more elegant way to do what
> ...

You can try to put your code through pylint. It will give you some automatic
critique.

--
Oinopion

George Sakkis
Guest
Posts: n/a

 02-08-2008
On Feb 8, 3:40 pm, Arnaud Delobelle <(E-Mail Removed)> wrote:

> On Feb 8, 7:20 pm, "Zack" <(E-Mail Removed)> wrote:
>
>
>
> > Hi all. I'm just starting to pick up python. I wanted to play with nested
> > lists so first I wrote a little bit of code to create arbitrarily nested
> > lists (grow). Then I wrote a breadth first search. I'm putting this small
> > snippet up asking for criticism. Was there a more elegant way to do what I'm
> > doing? Anything that goes against convention? Anything that fingers me as a
> > c++ programmer? Are there standard modules that do these kind of things?
> > Thanks for any feedback.

>
> > ##############################
> > from random import randint

>
> > Val = 0

>
> > def grow(L,depth):
> > '''grows L by appending integers and arbitrarily nested lists with a
> > maximum
> > depth. Returns L.'''
> > global Val
> > if depth == 0:
> > return L
> > else:
> > choice = randint(1,2)
> > if 1 == choice:
> > # add a numerical literal
> > Val += 1
> > L.append(Val)
> > return grow(L,depth-1)
> > elif 2 == choice:
> > # add a list
> > L.append( grow([],depth-1) )
> > return grow(L,depth-1)

>
>
> 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

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

Zack
Guest
Posts: n/a

 02-09-2008
On Feb 8, 4:32 pm, George Sakkis <(E-Mail Removed)> wrote:
> On Feb 8, 3:40 pm, Arnaud Delobelle <(E-Mail Removed)> wrote:
>
>
>

<snip my original post>

>
> > 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
>
> 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):
'''

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

TerryP
Guest
Posts: n/a

 02-17-2008
Tomek Paczkowski wrote:
> You can try to put your code through pylint. It will give you some
> automatic critique.
>

There is a pylint !?

That one is defiantly making my workstation later just for fun hehe.

--
There seems no plan because it is all plan.
-- C.S. Lewis

John Machin
Guest
Posts: n/a

 02-17-2008
On Feb 17, 4:42 pm, TerryP <(E-Mail Removed)> wrote:
> Tomek Paczkowski wrote:
> > You can try to put your code through pylint. It will give you some
> > automatic critique.

>
> There is a pylint !?
>
> That one is defiantly making my workstation later just for fun hehe.
>

See if you can find an englint while you are at it hehehe.

Dan Bishop
Guest
Posts: n/a

 02-17-2008
On Feb 8, 7:30 pm, Zack <(E-Mail Removed)> wrote:
>[snip]
>
> 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.
>
>[code example snipped]

Your functions look like good candidates for generators, but I
wouldn't mock you for using while loops.

I will say, however, that hasattr(item, '__iter__') isn't a perfect
way of checking whether an object is iterable: Objects that just
define __getitem__ are iterable too (e.g., UserList).

Matthew Marshall
Guest
Posts: n/a

 02-17-2008
Dan Bishop wrote:
> I will say, however, that hasattr(item, '__iter__') isn't a perfect
> way of checking whether an object is iterable: Objects that just
> define __getitem__ are iterable too (e.g., UserList).

Speaking of which, what *is* the best way to check if an object is
iterable?

I always wrap iter(item) in a try/except block, but is there an
isiterable() function somewhere?

MWM

George Sakkis
Guest
Posts: n/a

 02-17-2008
On Feb 17, 10:17 am, Matthew Marshall <(E-Mail Removed)>
wrote:
> Dan Bishop wrote:
> > I will say, however, that hasattr(item, '__iter__') isn't a perfect
> > way of checking whether an object is iterable: Objects that just
> > define __getitem__ are iterable too (e.g., UserList).

>
> Speaking of which, what *is* the best way to check if an object is
> iterable?
>
> I always wrap iter(item) in a try/except block,

Yes, that's the most foolproof way.

> but is there an
> isiterable() function somewhere?

Not AFAIK, but if I had to write one, I would use

isiterable = lambda x: hasattr(x, '__iter__') or
hasattr(x, '__getitem__')

In Python 3 it will be isinstance(x, Iterable).

George