Effective Python C2. 나머지를 모두 잡아내는 언패킹

3 분 소요

Introduction

기본 언패킹의 경우 시퀀스의 길이를 알아야 사용할 수 있다는 단점이 있다. 예를 들어,

fruits = ['apple', 'grape', 'banana', 'melon']
first_fruit, second_fruit = fruits

위와 같은 코드는 길이가 달라 에러를 일으킨다. 그렇다면 길이와 상관없이 앞에 두 개 원소를 가져오려면 어떻게 해야할까?

리스트 슬라이싱도 방법 중 하나다.

first_fruit, second_fruit = fruits[:2]

그러나 인덱스와 슬라이스로 인해 보기가 좋지는 않다.

더 좋은 방법이 있다.

Best WAY 13 : 슬라이싱보다는 나머지를 잡아내는 언패킹을 사용하라

starred expression을 사용하면, 기본 언패킹에서 미처 못한 언패킹 원소들을 *이 붙은 변수에 다 담을 수 있다.

first_fruit, second_fruit, *other = fruits

별표 위치는 어디든지 상관없으나, 두 개 이상 달 수는 없다. 또는 *가 붙은 변수만 있어서도 안된다.

first_fruit, *other, last_fruit = fruits
*other, second_last_fruit, last_fruit = fruits
*other, mid_fruit, *other = fruits # error
*other = fruits #error

별표 식은 항상 list 인스턴스가 된다. 언패킹 시 남은 원소가 없을 경우 빈 리스트가 된다.

first_fruit, second_fruit, third_fruit, last_fruit, *other = fruits

언패킹 방법을 이용하면, 헤더가 있는 데이터들, 예를 들면 csv 데이터의 헤더 부분과 나머지를 쉽게 나눠서 처리할 수 있다.

data = [['id', 'name'], [12, '홍길동'], [14, '권기홍']]

header, *rows = data
print(header)
print(len(rows))

Discussion

  • 언패킹은 할당문에서 오른쪽이 아니라 왼쪽에서도 쓰일 수 있으며, 할당 시 남는 원소들을 *가 붙은 객체(리스트)에 넣거나 반대로 길이가 최소 N개인 시퀀스에서 N개의 원소를 편리하게 언패킹할 수 있도록 한다.

코딩 테스트 문제를 풀 때 아래처럼 사용해보았다.
rec 리스트의 원소가 command, id, nickname 3개를 담거나, command, id 2개만 담을 수 있어 *연산자를 썼다.

# https://school.programmers.co.kr/learn/courses/30/lessons/42888
from collections import deque

def solution(record):
    result = []
    nicdict = dict()
    sequence = deque()
    
    for rec in record:
        command, *id_nic = rec.split()
        _id = id_nic[0]
        if command == 'Enter' or command == 'Change':
            nicdict[_id] = id_nic[-1]
        if command == 'Enter' or command == 'Leave':
            sequence.append([command, _id])
                
    while sequence:
        command, _id = sequence.popleft()
        if command == 'Enter':
            result.append(f"{nicdict[_id]}님이 들어왔습니다.")
        else:
            result.append(f"{nicdict[_id]}님이 나갔습니다.")
    
    return result

Summary

  • 언패킹 대입에 별표 식을 사용할 경우 언패킹 패턴에 대입되지 않는 부분을 리스트에 넣을 수 있다.
  • 별표 식은 어떤 위치든 넣을 수 있다. 단, 2개 이상 넣을 수 없으며 최소 1개 이상의 필수로 대입할 변수가 있어야 한다.
  • 리스트를 겹치지 않게 여러 조각으로 나눈다면 슬라이싱과 인덱싱보다는 나머지를 모두 잡아내는 언패킹을 활용하자.

Reference

파이썬 코딩의 기술 제 2판. - 브렛 슬리킨 지음 / 오현석 옮김