DEV Community

Cover image for Lessons From Advent of Code: Tuple Unpacking
Erik Anderson
Erik Anderson

Posted on

Lessons From Advent of Code: Tuple Unpacking

About 15 days ago, I gave up on Advent of Code for this year. Partly because I wanted to focus on finishing a comp sci certificate and prepare for a data science bootcamp. But also because they were getting hard. Now that it's Christmas, I'm letting myself look at solutions.

SPOILER ALERT: This post includes solutions to Advent of Code 2019 Day 02.

To add some learning value to this, I'll be writing some blog posts on lessons I learn from those solutions. I'll start with Day 02. I actually solved this one myself, so I'll be comparing aspects of my solution with that by Joel Grus.

One quickly apparent difference is that he used tuple unpacking to simplify a portion of the code.

Tuple unnpacking works like this:

In [1]: a, b, c = 3, 4, 5

In [2]: a
Out[2]: 3

In [3]: b
Out[3]: 4

In [4]: c
Out[4]: 5
Enter fullscreen mode Exit fullscreen mode

As you can see, the code in line In [1]: assigns 3 to a, 4 to b, and 5 to c. But why did that work?

Let's back up. A tuple is a fundamental data structure in python. The syntax to create a tuple is like this:

In [7]: my_tuple = 3, 4, 5, 'foo', 'bar'

In [8]: my_tuple
Out[8]: (3, 4, 5, 'foo', 'bar')
Enter fullscreen mode Exit fullscreen mode

Note also that you will some times see things like my_tuple = (3, 4, 5, 'foo', 'bar'), but these parentheses are not strictly required.

Tuples in python are like lists, except that they are immutable; once created they cannot be changed.

Like lists, tuples can contain different data types; in this case we saw int and str.

On the line a, b, c = 3, 4, 5, a few steps happen in the background. (3, 4, 5) gets packaged as a tuple. Then python attempts to store this tuple to the variable on the left side of the equation. Finding not one variable, but the tuple of variables (a, b, c), it unpacks both (3, 4, 5) and (a, b, c), matching up the numberes and variables in order.

Note that this process is also called multiple assignment because, well, it assigns multiple variables in one line.

What is this useful for? Here's one use case from Joel's solution.

But first I'll show a (out of context) portion of my (rather ugly) solution. Don't worry too much about what is happening, just note the convoluted syntax. That's a lot of info packed onto one line!

elif tape[current_index] == 1:
tape[tape[current_index + 3]] = tape[tape[current_index + 1]] + tape[tape[current_index + 2]]     
Enter fullscreen mode Exit fullscreen mode

That's a long, intricate line. It would be nice if we could shorten it.

Joel does this by specifying opcode = program[pos], loc1 = program[pos + 1], loc2 = program[pos + 2], loc3 = program[pos + 3], leading to code that looks like this:

if opcode == 1:
            program[loc3] = program[loc1] + program[loc2]
Enter fullscreen mode Exit fullscreen mode

The code to assing opcode, loc1, loc2 and loc31 could go on four separate lines, but here's where tuple unpacking becomes relevant. Joel does all of those assignments in one line.

opcode, loc1, loc2, loc3 = program[pos], program[pos + 1], program[pos + 2], program[pos + 3]    
Enter fullscreen mode Exit fullscreen mode

That code (on the second line of this sample) creates a tuple of integers on the right ride and passes it to the left side, where it gets unpacked into opcode, loc1, loc2, and loc3.

What's the advantage? It saves 3 lines of code. Maybe that's a small gain for a whole blog post, but tuple unpacking gets used in a wide variety of situations in Python.

And there's tuple unpacking applied to assignment, all wrapped up for Christmas!

Top comments (4)

Collapse
 
moopet profile image
Ben Sinclair

I don't like this sort of thing for assignments. I think readability suffers too much.

It makes it harder to see at a glance that loc2 and program[pos + 2] are the matching things where the assignment is happening. It gets worse when the names are long (like in this example) and should be wrapped across the next line.

It also makes it harder to merge changes if things aren't kept to one assignment per line.

Collapse
 
datadeverik profile image
Erik Anderson

Interesting point. Would you reccomend doing the assignment on four lines? I do see the readability advantage of that.
As I look back on this, assigning the loc variables does more for readability then the tuple assignment does.
I think it's worth adding that this is something Joel Grus hacked to gether, so I don't know whether he would write code this way in all situations.

Collapse
 
philipstarkey profile image
Phil Starkey

Given the data is in a list, and sequential, it would be clearer to just directly unpack the list, rather than using an intermediate tuple:

opcode, loc1, loc2, loc3 = program[pos:pos+4]

I think that's readable. But if there isn't an existing relationship between the values, assigning across multiple lines is definitely better for the reasons Ben suggested.

Thread Thread
 
datadeverik profile image
Erik Anderson

Thanks.

That's clever, and I agree it's readable.