[Tutor] a quetion on "There should be one and preferabley one obvious way to do it"

Danny Yoo dyoo@hkn.eecs.berkeley.edu
Mon, 21 Jan 2002 03:16:28 -0800 (PST)


On Mon, 21 Jan 2002, Karthik Gurumurthy wrote:

> hi all,
> 
> this is what i read @ bruce eckel's python site. He says this is
> against Perl's "there is more than one way to do it"


Yes, according to the "Zen of Python":

    http://www.python.org/doc/Humor.html#zen

Python tries to maintain the idea that "There should be one-- and
preferably only one --obvious way to do it."


> For example,
> 
> map(None,l1,l2)
> 
> does the same thing as
> say
> 
> zip(l1,l2)


Yes, good point!  The problem is that people have argued that:

    map(None, l1, l2)

looked totally weird --- what did it mean to map 'None' against those two
lists?  Let's try it.

###
>>> l1, l2 = range(10), list('abcdefghij')
>>> map(None, l1, l2)
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e'), (5, 'f'), 
 (6, 'g'), (7, 'h'), (8, 'i'), (9, 'j')]
###

It "ruffle shuffles" or "zips" the two lists together!  How strange!  Yet
it's documented:

"""
map(function, list, ...)
Apply function to every item of list and return a list of the results. If
additional list arguments are passed, function must take that many
arguments and is applied to the items of all lists in parallel; if a list
is shorter than another it is assumed to be extended with None items. If
function is None, the identity function is assumed; if there are multiple
list arguments, map() returns a list consisting of tuples containing the
corresponding items from all lists (a kind of transpose operation). The
list arguments may be any kind of sequence; the result is always a list.
"""

It's documented... but yet, this behavior of map() is not "obvious" at a
first glance.  We talked about this a bit on Tutor back in August:

    http://mail.python.org/pipermail/tutor/2001-August/008204.html


and I'm sure we weren't alone in our confusion.  Python Enhancement
Proposal (PEP) 201 was born to address the 'map(None, l1, l2)' issue:

    http://python.sourceforge.net/peps/pep-0201.html

so that's why we have a zip() function, to take the load off of map().




> there are more ways of doin it
> 
> dict.has_key(key)
> is same as
> if key in dict

Yes, this uses the new iterator system that's part of Python 2.2.  It's
true that:

    dict.has_key(key)

and

    if key in dict

have similar effects, but there's another benefit to being able to do
this, and it applies specifically for the 'for loop' on dictionaries:

###
for key in dict:
###

There's actually a performance benefit to doing it this way with
iterators, as opposed to:

###
for key in dict.keys():
###

This benefit is explained in PEP 234 under the "Dictionary Iterators"
section:

    http://python.sourceforge.net/peps/pep-0234.html

but basically, it summarizes to the idea that Python won't have to
actually construct a list of a dictionary's keys before traversing them,
if it uses iterators.




> We have list comprehensions that work like maps

But for people to effectively use map(), people need to feel very
comfortable passing around functions as objects.  For many programmers,
being able to hold a function in our hand:

###
>>> def square(x): return x * x
... 
>>> square
<function square at 0x811c504>
###

and being able to spontaneously build new functions:

###
>>> cube = lambda x: square(square(x))
>>> cube(42)
3111696
###

is weird as heck.  *grin*

List comprehensions are a bit easier to understand --- they use the syntax
in a way that does seem less alien than map().  The implementors explain
why they chose to add list comprehensions to the language here:

    http://python.sourceforge.net/peps/pep-0202.html



> So here too we have different ways of getting something done.

Yes, Python does allow the programmer to choose different ways to do
something.  Often, though, the designers have tried to make certain things
easier to do, like 'zipping' or constructing lists with list
comprehensions, things that people are doing a lot.  It's "syntactic
sugar": it's meant to make certain things more palatable.


I do agree that, at a certain point, the implementors should stop adding
syntactic features to Python.  (What were they thinking with 'print >>>'?!  
*sigh*)  For the most part, though, I think they've had pretty good taste.




By the way, you might be interested in the technetcast.com talk about
the "Lightweight Languages Workshop" at MIT:

    http://technetcast.ddj.com/tnc_catalog.html?item_id=1295

In particular, Shriram Khrishnamurthi's talk, "The Swine Before PERL" does
address the idea that adding syntax to make things easier might not be an
optimal approach to design a language.  It's a lot of fun to listen to an
"academic geek", and he does touch on the questions that you're asking.

    http://technetcast.ddj.com/tnc_play_stream.html?stream_id=644



Anyway, I hope I didn't sound too shrill.  *grin* Now I'm going to sleep.  
Talk to you later!