[Python-3000] Best Practices essays
Adam DePrince
adam.deprince at gmail.com
Fri Mar 24 08:06:33 CET 2006
On Thu, 2006-03-23 at 21:05 -0500, Edward C. Jones wrote:
> "Brett Cannon" <brett at python.org> wrote:
>
> > Right. I am really starting to think that having a group of Best
> > Practices essays that discuss common Python idioms might be handy.
> > Part tutorial, part advanced usage, they would provide a way for
> > people to have a place to go to find out expected usage of things
> > such as iterators without having to discover this kind of thing the
> > hard way. Could also help us see where possible improvements could
> > come in for Py3K if we write them from the perspective of 2.x, or
> > even how things improve if we write them for Py3K.
>
> That's a good idea. Include everything from m * [n * [0]] to pickling
> classes with __new__. For the latter, Google on "pickling a
> subclass of tuple".
Sort of like a cookbook? Martelli, Ravenscroft and Ascher beat you to
it.
Yes, while "There should be one -- and preferably only one -- obvious
way to do it", the truth is there are many ways of doing the same thing
- and each way will have its trade-offs and underlying philosophy that
will, from its authors perspective, make it the one way.
I don't want to discourage your efforts in creating this, but self
discovery of the best way to do things via the "hard way" is important.
I always like to say that experience is simply a measure of how much
stuff you have broken over your career.
Now, as for your example m * [ n * [0]], I would exclude it from a best
practices document. If your goal is to create a two dimensional array
of numbers, it doesn't work. The first part, n* [0] is right, you are
creating a list of n zeros, and when you say l[x]=y you are replacing
that element.
The second part, m *, is wrong. You are creating a list of m references
to the same list of n zeros.
Look at the following:
>>> m = 5
>>> n = 10
>>> l = m * [n * [0]]
>>> l[3][5] = 1
>>> l
[[0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0,
0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0,
1, 0, 0, 0, 0]]
>>>
I don't think that is what you had in mind.
One "quick and dirty" way of fixing that is:
l = map( list, m * [n * [0] ])
Now it works.
>>> l = map( list, m*[n*[0]] )
>>> l[3][5] = 1
>>> l
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0,
0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0,
0, 0, 0, 0, 0]]
>>>
But there are other ways.
>>> l = [n*[0] for _m in xrange( m )]
>>> l[3][5] = 1
>>> l
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0,
0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0,
0, 0, 0, 0, 0]]
[adam at localhost ~]$ python2.4 -mtimeit -s 'from numarray import
array;n=50;m=100' 'a = map( list, m * [n * [0] ])'
10000 loops, best of 3: 86.6 usec per loop
[adam at localhost ~]$ python2.4 -mtimeit -s 'from numarray import
array;n=50;m=100' 'a = [n*[0] for _m in xrange( m )]'
10000 loops, best of 3: 105 usec per loop
Which is best practice? Well, if you are doing real bona-fide
scientific work, best practice is to install numpy and say
import numarray
a = array( (0,)*(n*m), shape=(n,m)) # default type is 32 bit signed int
a-=a # To zero the array, without initial
# data, we get random junk.
[adam at localhost ~]$ python2.4 -mtimeit -s 'from numarray import
array;n=50;m=100' 'a = array( shape=(n,m));a-=a'
10000 loops, best of 3: 25.2 usec per loop
[adam at localhost ~]$
Well, which is best practice? Numpy beats plain old lists by a factor
of 3, and all of your subsequent computation is likely to be faster too,
but it requires an addition to python.
Cheers - Adam DePrince
More information about the Python-3000
mailing list