[Tutor] General Information Request

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Tue Sep 6 22:57:01 CEST 2005



On Tue, 6 Sep 2005, Lane, Frank L wrote:

> I found a really neat technique on the web using a built in called
> "apply", with it you can do struct.pack() using an array for the values.
> I can't find the technique in the release documentation and what's there
> says apply is deprecated, use the new function (**args, *kwargs) or
> something like that.


Hi Frank,

Python allows us to write functions that take a variable number of
arguments.  (For the moment, let's ignore the kwargs stuff.)

For example:

######
>>> def wave_at_all(*people):
...     for p in people:
...         print "waving at", p
...
>>>
>>> wave_at_all()
>>>
>>> wave_at_all("euclid")
waving at euclid
>>>
>>> wave_at_all("frank", "lloyd", "wright")
waving at frank
waving at lloyd
waving at wright
######


When we have these functions that can take variable number of arguments,
it's often nice to be able to feed a list directly into them, without
having to destructure them.


That's where apply comes in:

######
>>> apply(wave_at_all, ["jane", "doe"])
waving at jane
waving at doe
######

Without apply, this example might have been written as:

######
some_list = ['jane', 'doe']
first_name, second_name = some_list
wave_at_all(first_name, second_name)
######

But the problem with this, though, is that this approach doesn't scale: it
doesn't work for lists of arbitrary length, because in the general case,
we won't know in advance how many elements we need to "destructure" or
yank out of a list.

So one reason why apply() exists is to allow us to use
variable-length-argument-eating functions with lists.  (That was a
mouthful.  *grin*)  It's not the only reason, but it's a big one.


Notationally, apply() seemed a little weird to many Python programmers, so
the Python implementors added an alternative syntax in Python 2.0:

    apply(some_function, list_of_arguments)

        ==>

    some_function(*list_of_arguments)

(See: http://www.amk.ca/python/2.0/index.html#SECTION0001010000000000000000)


Does this make sense so far?  Please feel free to ask questions about
this.




> I also saw a technique for building a dictionary out of two arrays,
> which I also can't read:
>
>     dict([(['one', 'two'][i-2], i) for i in (2,3)])
>
> Is this just something that I have to get accustomed to or are there
> pointers that help us read python-speak better?

I can't read this either.  Truthfully, this looks horrible.  *grin*


What's happening is that there's a list comprehension nested in there, and
the expression as a whole feels very convoluted to me.  Here, let's break
it down a bit.

    mapping = dict([(['one', 'two'][i-2], i) for i in (2,3)])

        ==>

    keys_and_values = [(['one', 'two'][i-2], i)
                       for i in (2, 3)]
    mapping = dict(keys_and_values)


This also looks fairly ugly.  (It also worries me because it looks like
there's an off-by-one bug: why is 'one' being mapped to 2?)


We can remove the use of the list comprehension altogether:

    keys_and_values = [(['one', 'two'][i-2], i)
                       for i in (2, 3)]
    mapping = dict(keys_and_values)

        ==>

    keys = ['one', 'two']
    values = [2, 3]
    mapping = dict(zip(keys, values))



Best of wishes to you!



More information about the Tutor mailing list