Advanced Python Constructs

Author: Szymon Lipiński
Published at: 2016-09-06

A couple of more advanced, not wildly used Python constructs like list comprehension, dictionary comprehension, map, and filter.

All examples are using Python 3.5.

List Comprehension

This is a very nice way to create a list. Much shorter, and more clear, unless you don’t know the syntax. Instead of creating a list with a multilevel for loop.

Let’s get a list of 100 numbers from 1 to 100, and for all smaller than 11, let’s get this value squared. So basically I need to get a list like:

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

The simple way of implementing such a thing would be the following code:

res = []
for i in range(1,101):
    if i < 11:
        res.append(i*i)

However, using a list comprehension it can be:

[i*i for i in range(1, 101) if i < 11]

Let’s read it from the middle:

So basically, there is a generator which returns one value at a time, which is stored in the i variable, then the if part is applied, if returns True, then the i*i is stored in the list, if returns False, then we take the next value from the generator.

Dictionary Comprehension

This is a similiar construct to the above one, but it creates a dictionary. The syntax is similar, the only difference is: brackets, and key:value part instead of a single value.

Let’s create a dictionary using the previous list comprehension. The key would be the number, value would be the number squared:

{i:i*i for i in range(1, 101) if i < 11}

the returned value is:

{1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100}

As you can see there are just two differences:

Using Filter

There is quite a small set of functional functions like filter. The basic syntax is:

filter(function, iterable)

Basically this function takes a function, and a list, and returns a generator returning a list for which the function returns True.

Let’s now use it for filtering the values 1..100 from the generator to get the first 10:

f = filter(lambda x: x < 11, range(1, 101))
list(f)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

The above code can be also written like this:

def check_smaller_than_11(x):
    return x < 11

f = filter(check_smaller_than_11, range(1, 100))
[x for x in f]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Using Map

Map function is similar to filter, the arguments are the same:

map(function, iterable)

This function returns a generator, which returns exactly the same number of values as were in the the iterable, but each value is a result fo the function.

So if we have a list: [1, 2, 3], and a function: fun, then map(fun, [1, 2, 3] returns a generator, which returns values: [map(1), map(2), map(3)].

Let’s make the same list as in the list comprehension example. Instead of this:

[i*i for i in range(1, 101) if i < 11]

I will use map and filter:

m = map(lambda x: x*x, filter(lambda x: x<11, range(1, 101)))
list(m)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

So basically:

Final Notes

Which solution is better? I don’t know. Pyflakes is not happy about map/filter saying This could be changed to list comprehension.

On of the huge cons of using lambdas in the following examples is that lambda can be just a one liner in Python. However you can always write a separate function, and just use it instead of the lambda.

On the other hand if you need to use the same condition in a couple of list comprehensions, it is always better to move them into one separate function, so the code won’t be duplicated.

This function then can be used in a list comprehension like:

def fun(x):
    return True if x < 1 else return False

[x for x in gen if fun(x)]

but you can also use the same function in filter:

filter(fun, gen)

As usually all the solutions have pros, and cons, the real life choice usually depends on many different aspects.

The comments are disabled. If you want to write something to me, you can use e.g. Twitter.