DEV Community

Prayson Wilfred Daniel
Prayson Wilfred Daniel

Posted on

Unpack Like A Pythonista

A Pythonista's ways of data unpacking.

To index or to unpack, that is the question. During a code review, I came across unpleasant-looking code. For me, coding is an art. It tells stories about us. I love beautiful, creative and artistic stories. Thus, I love beautiful and creative code.

Back to the code review. The unpleasant "looking" code emerged from an index accessing of data.

# task A: get jack and the rest
friends_data = ["jane", "john", "jill", "jack", ]

# the usual indexing
jack = friends_data[-1] # -1 the last element in data | data[3] index 3, 4th element
rest = friends_data[:-1] # all but the last element

print(f"👋 hello, {jack!r} out of the {rest=}!")
# "👋 hello, 'jack' out of the rest=['jane', 'john', 'jill']!"
Enter fullscreen mode Exit fullscreen mode

As data become more complex, unpleasant-looking index accessing emerges.

# task B: get jack and his value (23)
data = [("jane", 21), ("john", 32), ("jill", 45), ("jack", 23), ]

# the usual indexing
jack = data[-1][0]
jacks_value[-1][1]

print(f"This is {jack!r} with the value {jacks_value}!")
# "This is 'jack' with the value 23!"
Enter fullscreen mode Exit fullscreen mode

A prettier solution could be pattern matching. For example in Rust 🦀, we could perform destructuring assignments with match.

// task A: get jack and the rest

// unpacking/destructuring assignment
fn main() {
    let friends_data = ["jane", "john", "jill", "jack", ];
    let data = [("jane", 21), ("john", 32), ("jill", 45), ("jack", 23),];

    match friends_data {

        [.., jack] =>
            println!("👋 Hey, rust, this is {jack}!"),   
    }

    match data {
        [.., (jack, jacks_value)] =>
            println!("Oh, rust, this is {jack} with the values {jacks_value}!")
    }
}

// cargo run
// >> 👋 Hey, rust, this is jack!
// >> Oh, rust, this is jack with the values 23!
Enter fullscreen mode Exit fullscreen mode

Python 🐍 offers destructuring assignments too. It brings beauty back to data accessing.

# task A: get jack and the rest

*rest, jack = friends_data
print(f"👋 hello, {jack!r} out of the {rest=}!")
# "👋 hello, 'jack' out of the rest=['jane', 'john', 'jill']!"

# task B: get jack and his value (23)

*_, (jack, jacks_value) = data # *_ since we dont need the rest we throw them away
print(f"This is {jack!r} with the value {jacks_value}!")
# "This is 'jack' with the value 23!"
Enter fullscreen mode Exit fullscreen mode

It's even prettier when you unpack nested weird data.

weird_data = [("jack", 23),]
[(jack, jacks_value), ] = weird_data 
print(f"This is still {jack!r} with the value {jacks_value}!")
# "This is still 'jack' with the value 23!"
Enter fullscreen mode Exit fullscreen mode

To index or to unpack? I hope the answer is less unclear. Until then, keep on unpacking ...

Top comments (0)