파이썬에서 too many values to unpack 또는 not enough values to unpack이 발생하면 먼저 좌변 변수 수와 실제 iterable 항목 수가 같은지 확인해야 합니다. split() 결과, 함수 반환값, 반복 대상, 파일 입력 행 가운데 어디의 구조가 예상과 달라졌는지 확인한 뒤에 변수 추가나 *rest, maxsplit, partition(), 입력 거부를 선택하는 것이 안전합니다.
언패킹 오류의 핵심은 양쪽 구조의 불일치입니다
다음 코드는 두 값을 기대하지만 실제 문자열을 그대로 순회하면 문자가 항목으로 전달될 수 있습니다.
name, value = "cpu=80"
여기서 중요한 것은 문자열의 겉보기 모양이 아니라 언패킹 대상 iterable이 실제로 몇 개의 항목을 내놓는가입니다. 스타가 없는 언패킹은 iterable 항목 수와 좌변 target 수가 같아야 합니다. 따라서 오류 메시지의 expected 2는 좌변이 두 대상을 기대했다는 뜻으로 읽고, 우변의 실제 구조를 출력하거나 단계별로 나누어 확인합니다.
parts = "cpu=80".split("=")
print(parts, len(parts))
name, value = parts
반대로 not enough values to unpack은 입력에 구분자가 없어 기대한 수만큼 항목이 나오지 않은 경우를 먼저 의심할 수 있습니다. 다만 함수 반환값이나 API 응답은 해당 계약을 따로 확인해야 하므로, 오류 문구만 보고 split() 문제라고 단정하지 않는 편이 좋습니다.
먼저 split 결과와 입력 원문을 확인합니다
구분자로 나눈 결과가 고정된 두 필드라는 계약이라면, 언패킹 전에 필드 수를 검사하면 원인을 입력 행까지 좁힐 수 있습니다.
def parse_setting(line: str) -> tuple[str, str]:
raw = line.rstrip("\n")
fields = raw.split("=")
if len(fields) != 2:
raise ValueError(f"구조가 다른 입력: {raw!r}, fields={len(fields)}")
name, value = fields
return name.strip(), value.strip()
구분자를 지정한 split()은 연속 구분자를 빈 문자열 필드로 취급하므로 a==b 같은 입력도 예상과 다른 값이 될 수 있습니다. 값 안에 같은 구분자가 들어올 수 있다면 단순히 좌변 변수를 늘리는 것은 입력 계약을 흐릴 수 있습니다.
값 안에 구분자가 있을 때: maxsplit과 partition
첫 번째 구분자 왼쪽을 이름으로, 나머지를 값으로 보존하려는 형식이라면 split("=", maxsplit=1)처럼 경계를 명시할 수 있습니다.
name, value = "query=a=b".split("=", maxsplit=1)
split(maxsplit)을 지정하면 최대 분할 횟수는 maxsplit이고 결과 원소 수는 최대 maxsplit + 1입니다. 이 방식은 구분자가 반드시 있어야 하고, 앞뒤 두 부분만 필요할 때 적합합니다.
구분자 자체가 있었는지도 구분해야 한다면 partition()이 더 읽기 쉽습니다.
name, separator, value = "query=a=b".partition("=")
if not separator:
raise ValueError("설정 구분자가 없습니다")
partition()은 첫 구분자를 기준으로 앞부분·구분자·뒷부분을 반환합니다. 구분자가 없을 때도 반환 형태가 유지되므로, separator를 검사해 입력 거부 여부를 명시할 수 있습니다. 이 차이를 모르고 partition() 결과를 두 변수에 받으면 또 다른 언패킹 오류가 발생합니다.
*rest는 무조건적인 오류 회피가 아닙니다
추가 필드가 정상적으로 존재할 수 있고 이를 보존해야 한다면 스타 target을 사용할 수 있습니다.
head, *rest = "a,b,c".split(",")
스타 target은 남은 항목을 리스트로 받으며 남은 항목이 0개일 수도 있습니다. 그러므로 *rest를 사용한 뒤에는 추가 값이 있어야 하는지, 없어도 되는지 다시 검증해야 합니다.
head, *rest = raw.split(",")
if not rest:
raise ValueError("세부 항목이 없습니다")
반복 대상이 레코드 형식인데 필드가 늘어난 것이라면 *rest로 조용히 삼키기보다 원본 계약을 업데이트하거나 입력을 보류하는 편이 낫습니다. 반대로 로그처럼 첫 토큰만 필요하고 뒤의 내용은 가변적인 형식이라면 *rest를 사용한 뒤 다시 합치는 선택도 가능합니다.
파일 입력 행은 행 번호와 원문을 함께 남깁니다
파일 객체는 반복문으로 한 줄씩 순회할 수 있고, 줄바꿈을 제거한 뒤 필드 수를 확인할 수 있습니다. 잘못된 행을 만났을 때는 최소한 행 번호·원문·필드 수를 기록해야 나중에 upstream 데이터 문제인지 파서 문제인지 구분할 수 있습니다.
for line_no, line in enumerate(settings_file, start=1):
raw = line.rstrip("\n")
fields = raw.split("=", maxsplit=1)
if len(fields) != 2:
print(f"보류: line={line_no}, raw={raw!r}, fields={len(fields)}")
continue
name, value = fields
process(name.strip(), value.strip())
continue로 건너뛰어도 되는지는 데이터의 성격으로 결정해야 합니다. 선택적인 설정이나 일부 로그라면 보류 목록을 남기고 진행할 수 있지만, 금액·권한·배치 대상처럼 한 행이 누락되면 전체 결과가 달라지는 입력이라면 즉시 중단하거나 작업을 보류하는 편이 안전합니다. except ValueError: pass처럼 오류를 삼키면 누락 범위를 알 수 없게 됩니다.
오류가 나면 이 순서로 결정합니다
- 오류가 난 줄의 우변이 실제로 어떤 타입과 구조인지 확인합니다.
split()결과, 함수 반환값, 반복 대상, 파일 행 가운데 원인을 분리합니다.- 고정된 필드 수가 계약이라면 길이를 검사하고 원문과 위치를 기록합니다.
- 값 내부의 구분자가 정상이라면
maxsplit또는partition()으로 경계를 표현합니다. - 추가 항목이 정상적인 가변 데이터일 때만
*rest로 보존합니다. - 형식이 틀린 행을 건너뛸지 중단할지는 데이터 손실의 영향을 기준으로 정합니다.
이 순서를 따르면 too many values to unpack을 단순히 변수 수를 늘려 없애는 대신, 입력 형식과 코드의 기대가 어긋난 지점을 수정할 수 있습니다. 특히 자동화에서는 오류를 없애는 것보다 잘못된 입력을 놓치지 않는 것이 더 중요합니다.
다음에 확인할 질문
- 파이썬 split 결과의 필드 수를 어디에서 검증할 것인가?
- 파일 입력 행 오류를 기록하고 중단할 기준은 무엇인가?
- API 응답 구조가 달라질 때 반환값과 입력 계약을 어떻게 검증할 것인가?