help with map function

M

Michael

In the book 'Text Processing Python,' they present a function that I'm
having a real hard time understanding.

apply_each = lambda fns, args=[]: map(apply, fns, [args]*len(fns))


I understand that the lamda statement is passing a function that
accepts a function and an iterable variable as arguments.

The function passed by lamda is a map statement that maps the function
in the arguement list against each item in the iterable variable.

However, I don't understand what is happening in the 3rd arguement of
map though. What does [args]*len(fns) do?
 
D

Duncan Booth

Michael said:
In the book 'Text Processing Python,' they present a function that I'm
having a real hard time understanding.

apply_each = lambda fns, args=[]: map(apply, fns, [args]*len(fns))
A lambda creates an anonymous function. Assigning a lambda directly to a
variable is simply an exercise in obfuscation. The same code can be more
clearly expressed:

def apply_each(fns, args=[]):
return map(apply, fns, [args]*len(fns))


These days you can express the same thing more clearly with a list
comprehension:

def apply_each(fns, args=[]):
return [ fn(*args) for fn in fns ]

In general it would probably be better to define it as:

def apply_each(fns, *args, **kw):
return [ fn(*args, **kw) for fn in fns ]

although this changes slightly how you call it.
I understand that the lamda statement is passing a function that
accepts a function and an iterable variable as arguments.

The function passed by lamda is a map statement that maps the function
in the arguement list against each item in the iterable variable.

However, I don't understand what is happening in the 3rd arguement of
map though. What does [args]*len(fns) do?
[args]*len(fns) is equivalent to [args, args, args, ...] where args is
repeated as often as there are elements in the list. It means that every
time apply is called it gets one of the functions and the args value as its
parameters.
 
M

michael.mata

Duncan said:
A lambda creates an anonymous function. Assigning a lambda directly to a
variable is simply an exercise in obfuscation. The same code can be more
clearly expressed:

def apply_each(fns, args=[]):
return map(apply, fns, [args]*len(fns))
I agree. I was so busy trying to wrap my head around this statement,
that I realize it was more complex than it had to be.
These days you can express the same thing more clearly with a list
comprehension:

def apply_each(fns, args=[]):
return [ fn(*args) for fn in fns ]

In general it would probably be better to define it as:

def apply_each(fns, *args, **kw):
return [ fn(*args, **kw) for fn in fns ]

although this changes slightly how you call it.

I don't have any experience working with *args, **kw arguments. From
what I've read, *args allows for an unknown number of arguments to
passed into a function and **kw allows for an unknown number of
key-value pairs to passed into a function. But from what I understand,
both are optional. This shouldn't change the how you call apply_each.
[args]*len(fns) is equivalent to [args, args, args, ...] where args is
repeated as often as there are elements in the list. It means that every
time apply is called it gets one of the functions and the args value as its
parameters.

I understand now. [args] can be a list of variables, including a list
of lists. Each variable within [args] is passed to the function called
within apply_each().
 
M

michael.mata

I don't have any experience working with *args, **kw arguments.
From what I've read, *args allows for an unknown number of
arguments to passed into a function and **kw allows for an
unknown number of key-value pairs to passed into a function.
But from what I understand, both are optional. This shouldn't
change the how you call apply_each.

I spoke too soon. If the function being called doesn't provide for
*args, or **kw then a TypeError exception will be thrown.
 
D

Duncan Booth

wrote:
I spoke too soon. If the function being called doesn't provide for
*args, or **kw then a TypeError exception will be thrown.

The original apply_each expected you to use it something like this:

def fn1(a,b,c): ... whatever ...
def fn2(a,b,c): ... whatever ...

result = apply_each([fn1, fn2], [1, 2, 3])

A revised version:

def apply_each(fns, *args, **kw):
return [ fn(*args, **kw) for fn in fns ]

could be called in a variety of ways:

result = apply_each([fn1, fn2], 1, 2, 3)
result = apply_each([fn1, fn2], *[1, 2, 3])
result = apply_each([fn1, fn2], a=1, c=3, b=2)
result = apply_each([fn1, fn2], **{'a': 1, 'c': 3, 'b': 2})

The functions actually being called don't need to know anything about how
they are invoked, they just need to get a suitable combination of
positional and/or keyword arguments.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top