Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How (in)efficient is a list comprehension if you don't assign it?

In this question, I'm having an argument with a commenter who argues that

for t in threads:
    t.join()

would be better than

[t.join() for t in threads]

Leaving the matter of "abusing comprehensions" aside - I tend to agree but I would like a one-liner for this: How (in-)efficient is my version (the second one) really?. Does Python materialize list comprehensions always / in my case or does it use a generator internally?

Would map(lambda t: t.join(), threads) be more efficient? Or is there another way to apply the function to each element in the list threads?

like image 901
Aaron Digulla Avatar asked Jan 29 '14 10:01

Aaron Digulla


2 Answers

A list comprehension will always produce a list object, in this case with the return values of all the t.join() calls. Python thus produces as list with None values of length len(threads) for you. Python will never try to optimize away the list object creation.

Using map() is also not any more efficient as you add additional stack pushes with the lambda. Just stick with the explicit for loop.

Really, for a series of thread joins there is no point in trying to micro optimize here. You are hurting readability for a non-critical piece of code.

In other words, I entirely agree with the commenter. Do not use a list comprehension or map() just for the side effects and saving yourself having to hit ENTER and create two lines of code.

Quoting the Zen of Python:

  • Readability counts.
like image 153
Martijn Pieters Avatar answered Nov 01 '22 18:11

Martijn Pieters


You can make a foreach that works as you want. I would recommend against it, as it's not a normal python way of doing things. Untested, but along the lines of this:

class foreach:
    def __init__(self, object_list):
        self.__object_list = object_list

    def __getattr__(self, name):
        def f(*args, **kwargs):
            for obj in self.__object_list:
                getattr(obj, name)(*args, **kwargs)
        return f


foreach(thread_list).join()

It pretty much creates a sort of proxy object that forwards any call with any parameters to all objects.

(I will most likely have a good chat if you if you would do this in my development team, but it does serve as an example of what is possible in python)

like image 21
Daid Braam Avatar answered Nov 01 '22 19:11

Daid Braam