List comprehensions were the point at which Ruby lost a little of it’s shine for me and I started to think that maybe the future belonged to Python.

I’ve been discovering a few neat tricks while I’ve been working on supporting a legacy API. Here’s a few code snippets demonstrating different ways to work with lists in python.

List Comprehensions

python tips full comprehensions explanation

List comprehensions are a concise way of building sequences such as list, dictionary, set or generators. You can bypass loop constructs with a nifty one-liner (although they don’t need to be one-liners).

List comprehension:

new_list = [expression(i) for i in old_list if filter(i)]

eg:

even_list = [n for n in range(10) if n % 2 == 0]

print(even_list)

=> [0, 2, 4, 6, 8]

I’ve been using list comprehensions to recreate complex object structures from a legacy API that I need to maintain and they rarely fit on one line:

v2_object = {'artists': [{
                          'name': 'Bonnie Tyler',
                          'id': 'X1'
                        },
                        {
                          'name': 'Chuck Berry',
                          'id': 'X2'
                        }]
            }
v1_object = {}
v1_object['names'] = [{"model": "collection.name",
                      "fields": {
                          "name": person["name"],
                          "id": person["id"],
                          "type": "person"
                        }
                      } for person in v2_object['artists']]

where

print(v1_object['names'])

=>

[
  {'model': 'collection.name',
  'fields': {
    'name': 'Bonnie Tyler',
    'id': 'X1',
    'type': 'person'}
    },
  {'model': 'collection.name',
  'fields': {
    'name': 'Chuck Berry',
    'id': 'X2',
    'type': 'person'}
  }
]

Enumerate()

python tips explanation

enumerate() is a built-in python function that allows you to loop while maintaining an automatic counter. The counter starts at zero unless you tell it otherwise with an optional start argument.

In my examples I will show it used in conjunction with the list_comprehension from above.

v1_object['names'] = [{"model": "collection.name",
                       "key": count,
                      "fields": {
                          "name": person["name"],
                          "id": person["id"],
                          "type": "person"
                        }
                      } for count, person in enumerate(v2_object['artists'])]

where

print(v1_object['names'])

=>

[
  {'model': 'collection.name',
  'key': 0,
  'fields': {
    'name': 'Bonnie Tyler',
    'id': 'X1',
    'type': 'person'}
    },
  {'model': 'collection.name',
  'key': 1,
  'fields': {
    'name': 'Chuck Berry',
    'id': 'X2',
    'type': 'person'}
  }
]

Itertools.chain()

itertools official docs

itertools is a module in python that has a collection of functions for iterating through lists and strings.

You need to import whichever function you want to use:

from itertools import chain

Chain takes a number of iterables (eg lists) as its arguments and combines them form a single iterable that can be looped over.

So again using the previous list comprehension. If we wanted to combine ‘artists’ and ‘managers’ in our v1_object[‘names’] we could simplify by using chain():

v2_object = {'artists': [{
                          'name': 'Artist 1',
                          'id': 'A1'
                        },
                        {
                          'name': 'Artist 2',
                          'id': 'A2'
                        }],
             'managers': [{
                          'name': 'Manager 1',
                          'id': 'M1'
                        },
                        {
                          'name': 'Manager 2',
                          'id': 'M2'
                        }]
            }
v1_object = {}
v1_object['names'] = [{"model": "collection.name",
                       "key": count,
                      "fields": {
                          "name": person["name"],
                          "id": person["id"],
                          "type": "person"
                        }
                      } for count, person in enumerate(chain(v2_object['artists'],v2_object['managers']), start=1000)]

where

print(v1_object['names'])

=>

[{'model': 'collection.name', 
  'key': 1000,
  'fields': {'name': 'Artist 1', 'id': 'A1', 'type': 'person'}},
  {'model': 'collection.name',
  'key': 1001,
  'fields': {'name': 'Artist 2', 'id': 'A2', 'type': 'person'}},
  {'model': 'collection.name',
  'key': 1002,
  'fields': {'name': 'Manager 1', 'id': 'M1', 'type': 'person'}},
  {'model': 'collection.name',
  'key': 1003,
  'fields': {'name': 'Manager 2', 'id': 'M2', 'type': 'person'}
  }
]