Neil
Neil

Reputation: 3291

Idiomatic way to call method on all objects in a list of objects

I have a list of objects and they have a method called process. In Python 2 one could do this

map(lambda x: x.process, my_object_list)

In Python 3 this will not work because map doesn't call the function until the iterable is traversed. One could do this:

list(map(lambda x: x.process(), my_object_list))

But then you waste memory with a throwaway list (an issue if the list is big). I could also use a 2-line explicit loop. But this pattern is so common for me that I don't want to, or think I should need to, write a loop every time.

Is there a more idiomatic way to do this in Python 3?

Upvotes: 11

Views: 17652

Answers (2)

scharette
scharette

Reputation: 9977

Since you're looking for a Pythonic solution, why would even bother trying to adapt map(lambda x: x.process, my_object_list) for Python 3 ?

Isn't a simple for loop enough ?

for x in my_object_list:
    x.process()

I mean, this is concise, readable and avoid creating an unnecessary list if you don't need return values.

Upvotes: 5

chepner
chepner

Reputation: 531145

Don't use map or a list comprehension where simple for loop will do:

for x in list_of_objs:
    x.process()

It's not significantly longer than any function you might use to abstract it, but it is significantly clearer.

Of course, if process returns a useful value, then by all means, use a list comprehension.

results = [x.process() for x in list_of_objs]

or map:

results = list(map(lambda x: x.process(), list_of_objs))

There is a function available that makes map a little less clunky, especially if you would reuse the caller:

from operator import methodcaller
processor = methodcaller('process')
results = list(map(processor, list_of_objs))
more_results = list(map(processor, another_list_of_objs))

If you are looking for a good name for a function to wrap the loop, Haskell has a nice convention: a function name ending with an underscore discards its "return value". (Actually, it discards the result of a monadic action, but I'd rather ignore that distinction for the purposes of this answer.)

def map_(f, *args):
    for f_args in zip(*args):
        f(*f_args)

# Compare:
map(f, [1,2,3])  # -- return value of [f(1), f(2), f(3)] is ignored
map_(f, [1,2,3])  # list of return values is never built

Upvotes: 12

Related Questions