Fork me on GitHub

Project Notes

#158 Lists with Indices

Revising methods for adding indexes to lists since PEP 3113 removed tuple parameter unpacking

Notes

In Python 3.0, PEP 3113 removed tuple parameter unpacking.

This means that, for example, implicit unpacking of tuples for a lambda like this will no longer work and will generate a syntax error:

lambda (x, y): x + y

Tuples now requires explicit unpacking, like this:

lambda x_y: x_y[0] + x_y[1]

Getting index of item while processing a list using map in python is a classic example of how automatic unpacking was used in the past:

Python 2.7.18 (default, Dec 26 2020, 15:56:25)
>>> ranked_users = ['jon','bob','jane','alice','chris']
>>> map(lambda (i, name): {'name': name, 'rank': i}, enumerate(ranked_users))
[{'name': 'jon', 'rank': 0}, {'name': 'bob', 'rank': 1}, {'name': 'jane', 'rank': 2}, {'name': 'alice', 'rank': 3}, {'name': 'chris', 'rank': 4}]

However in Python 3:

Python 3.7.3 (default, Dec 16 2020, 12:00:16)
>>> ranked_users = ['jon','bob','jane','alice','chris']
>>> map(lambda (i, name): {'name': name, 'rank': i}, enumerate(ranked_users))
  File "<stdin>", line 1
    map(lambda (i, name): {'name': name, 'rank': i}, enumerate(ranked_users))
               ^
SyntaxError: invalid syntax

There are a few ways to avoid this problem…

Explicit Tuple Unpacking

The easiest way of changing existing code is probably to simply convert implicit unpacking to explicit unpacking:

Python 3.7.3 (default, Dec 16 2020, 12:00:16)
>>> ranked_users = ['jon','bob','jane','alice','chris']
>>> map(lambda i_name: {'name': i_name[1], 'rank': i_name[0]}, enumerate(ranked_users))
<map object at 0x1097b0860>
>>> list(_)
[{'name': 'jon', 'rank': 0}, {'name': 'bob', 'rank': 1}, {'name': 'jane', 'rank': 2}, {'name': 'alice', 'rank': 3}, {'name': 'chris', 'rank': 4}]

Note: in Python 3, the map() function now returns an iterator, hence use of list() to unroll the result. See Views And Iterators Instead Of Lists

List Comprehension

Another approach is to simpley enumerate with a list comprehension, for example:

Python 3.7.3 (default, Dec 16 2020, 12:00:16)
>>> ranked_users = ['jon','bob','jane','alice','chris']
>>> [{'name': name, 'rank': i} for i, name in enumerate(ranked_users)]
[{'name': 'jon', 'rank': 0}, {'name': 'bob', 'rank': 1}, {'name': 'jane', 'rank': 2}, {'name': 'alice', 'rank': 3}, {'name': 'chris', 'rank': 4}]

Running The Examples

There are two example files:

Running with Python 2:

$ pyenv shell 2.7.18
$ ./py2_rank_players.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK
$ ./py3_rank_players.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Running with Python 3:

$ pyenv shell 3.7.3
$ ./py2_rank_players.py
  File "./py2_rank_players.py", line 12
    return map(lambda (i, player_info): add_rank(i, player_info), enumerate(player_list))
                      ^
SyntaxError: invalid syntax
$ ./py3_rank_players.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Credits and References

About LCK#158 python
Project Source on GitHub Return to the Project Catalog

LittleCodingKata is my collection of programming exercises, research and code toys broadly spanning things that relate to programming and software development (languages, frameworks and tools).

These range from the trivial to the complex and serious. Many are inspired by existing work and I'll note credits and references where applicable. The focus is quite scattered, as I variously work on things new and important in the moment, or go back to revisit things from the past.

This is primarily a personal collection for my own edification and learning, but anyone who stumbles by is welcome to borrow, steal or reference the work here. And if you spot errors or issues I'd really appreciate some feedback - create an issue, send me an email or even send a pull-request.

LittleArduinoProjects LittleModelArt More on my blog