Iterating over a function call

G

Gerald Britton

Hi -- I have many sections of code like this:

for value in value_iterator:
value_function(value)

I noticed that this does two things I don't like:

1. looks up "value_function" and "value" for each iteration, but
"value_function" doesn't change.
2. side effect of (maybe) leaking the iterator variable "value" into
the code following the loop (if the iterator is not empty).

I can take care of 2 by explicitly deleting the variable at the end:

del value

but I'd probably forget to do that sometimes. I then realized that,
in the 2.x series, I can accomplish the same thing with:

map(value_function, value_iterator)

and avoid both problems BUT map() returns a list which is never used.
Not a big deal for small iterables, I guess, but it seems messy. Upon
conversion to 3.x I have to explicitly list-ify it:

list(map(value_function, value_iterator))

which works but again the list returned is never used (extra work) and
has to be gc'd I suppose (extra memory).

It's easy to make a little function to take care of this (2.x):

from itertools import imap
def apply(function, iterable):
for item in imap(function, iterable):
pass

then later:

apply(value_function, value_iterator)

or something similar thing in 3.x, but that just adds an additional
function def that I have to include whenever I want to do something
like this.

So.....I'm wondering if there is any interest in an apply() built-in
function that would work like map() does in 2.x (calls the function
with each value returned by the iterator) but return nothing. Maybe
"apply" isn't the best name; it's just the first one that occurred to
me.

Or is this just silly and should I forget about it?
 
D

Diez B. Roggisch

So.....I'm wondering if there is any interest in an apply() built-in
function that would work like map() does in 2.x (calls the function
with each value returned by the iterator) but return nothing. Maybe
"apply" isn't the best name; it's just the first one that occurred to
me.

Or is this just silly and should I forget about it?

IMHO - yes. Looking up names is what python does all the time, trying to
microoptimize that away is silly. It is only justfied if you have
extremely timing-critical code.

And then, all you need to do is to say


def whatever():
_function = function
for value in values:
_function(value)

which will reduce lookup-time, as _function is found in locals() rather
than globals().

And any function that does something worthy will dwarf the second
namespace-lookup I'd say.

Diez
 
A

Arnaud Delobelle

Gerald Britton said:
Hi -- I have many sections of code like this:

for value in value_iterator:
value_function(value)

I noticed that this does two things I don't like:

1. looks up "value_function" and "value" for each iteration, but
"value_function" doesn't change.
2. side effect of (maybe) leaking the iterator variable "value" into
the code following the loop (if the iterator is not empty).

I can take care of 2 by explicitly deleting the variable at the end:

del value

but I'd probably forget to do that sometimes. I then realized that,
in the 2.x series, I can accomplish the same thing with:

map(value_function, value_iterator)

and avoid both problems BUT map() returns a list which is never used.
Not a big deal for small iterables, I guess, but it seems messy. Upon
conversion to 3.x I have to explicitly list-ify it:

list(map(value_function, value_iterator))

which works but again the list returned is never used (extra work) and
has to be gc'd I suppose (extra memory).

It's easy to make a little function to take care of this (2.x):

from itertools import imap
def apply(function, iterable):
for item in imap(function, iterable):
pass

then later:

apply(value_function, value_iterator)

or something similar thing in 3.x, but that just adds an additional
function def that I have to include whenever I want to do something
like this.

You have itertools.consume which is close to what you want:

consume(imap(func, iterable)) # 2.x

consume(map(func, iterable)) # 3.x

HTH
 
G

Gerald Britton

[snip[
You have itertools.consume which is close to what you want:

   consume(imap(func, iterable)) # 2.x

   consume(map(func, iterable)) # 3.x

HTH

It does! Though in my case this is simpler:

deque(imap(func, iterable), 0)

since the recipe for consume just calls deque anyway when you want to
eat up the rest of the iterable. It also solves the iterator-variable
leakage problem and is only a wee bit slower than a conventional
for-loop.
 
T

Terry Reedy

You have itertools.consume which is close to what you want:

consume(imap(func, iterable)) # 2.x

consume(map(func, iterable)) # 3.x

Consume is not in itertools. It is one of many recipes in the doc
(9.7.2). For exhausting an iterator, collections.deque(iterator, maxlen=0).
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top