왈러스 연산자 vs 일반 대입
Python 3.8에 들어온 := 연산자는 표현식 안에서 대입을 합니다. 일반 대입과 무엇이 다른지, 어디서 코드를 간결하게 만들고 어디서 오히려 해치는지 정리합니다.
지난 글에서 복사의 함정을 정리했다면, 이번 글은 비교적 가벼운 주제 하나를 다룬다. Python 3.8에서 들어온 왈러스 연산자(walrus operator) :=다. 생긴 모양이 바다코끼리(walrus)의 눈과 엄니를 닮았다고 해서 붙은 별명이고, 정식 명칭은 할당 표현식(assignment expression)이다. 이 작은 연산자 하나가 일반 대입 =과 어떻게 다른지, 그리고 언제 쓰는 게 좋고 언제 자제하는 게 좋은지 살펴본다.
대입을 표현식으로
핵심부터 말하면, 일반 대입 =은 문(statement)이고 왈러스 :=은 표현식(expression)이다. 문은 그 자체로 값을 갖지 않아서 다른 표현식의 일부로 끼워 넣을 수 없다. 그래서 다음은 문법 오류다.
if (n = len(data)) > 10: # SyntaxError — = 는 표현식이 아니다
...
반면 왈러스는 “이름에 값을 대입하면서, 그 값을 표현식의 결과로도 내놓는다.” 덕분에 if나 while의 조건 안에서 대입과 검사를 한 번에 할 수 있다.
if (n := len(data)) > 10: # n에 길이를 담으면서 동시에 10과 비교
print(f"{n}개는 너무 많습니다")
여기서 n은 대입되고, 그 값(len(data))이 곧바로 > 10 비교에 쓰인다. 대입과 사용을 한 자리에 모은 것이 왈러스의 전부다.
가장 잘 어울리는 자리 — while 루프
왈러스가 가장 빛나는 곳은 “값을 읽어서, 그 값이 어떤 조건이면 계속하는” 반복문이다. 왈러스가 없던 시절에는 같은 읽기 코드를 루프 앞과 루프 끝에 두 번 적어야 했다.
# 왈러스 없이 — readline()을 두 번 적는다
line = f.readline()
while line:
process(line)
line = f.readline()
# 왈러스로 — 대입과 조건을 한 줄에
while (line := f.readline()):
process(line)
읽는 코드가 한 곳으로 모이면서 중복이 사라지고, “읽은 게 있는 동안 처리한다”는 의도가 한 줄에 또렷해진다. 이처럼 읽기·계산과 그 결과의 검사가 짝을 이루는 패턴이 왈러스의 가장 자연스러운 용도다.
컴프리헨션에서 계산 재사용
또 다른 좋은 자리는 컴프리헨션이다. 같은 계산을 조건과 결과 양쪽에서 써야 할 때, 왈러스가 없으면 그 비싼 계산을 두 번 적게 된다.
# 왈러스 없이 — f(x)를 두 번 호출한다
result = [f(x) for x in data if f(x) is not None]
# 왈러스로 — 한 번만 계산해서 재사용
result = [y for x in data if (y := f(x)) is not None]
아래쪽은 f(x)를 단 한 번 호출해 y에 담고, 그 y를 조건 검사와 결과 양쪽에서 함께 쓴다. 계산이 무겁거나 부작용이 있는 함수일수록 이 중복 제거의 가치가 크다.
자제해야 할 때
좋은 도구도 남용하면 독이 된다. 왈러스가 코드를 오히려 읽기 어렵게 만드는 경우들이 있다.
가장 흔한 오용은 그냥 한 줄짜리 평범한 대입을 굳이 왈러스로 바꾸는 것이다. 표현식 안에 끼워 넣을 이유가 없는데 :=을 쓰면 괄호만 늘고 가독성은 떨어진다.
# 나쁨 — 그냥 대입이면 되는데 표현식으로 위장
print(total := a + b)
# 좋음 — 의도가 분명한 평범한 대입
total = a + b
print(total)
또 하나는 한 표현식에 왈러스를 여러 개 욱여넣거나, 함수 인자 한가운데서 깜짝 대입을 하는 것이다. 읽는 사람이 “여기서 변수가 언제 어떤 값으로 생겼지?”를 추적하게 만들면, 간결함을 얻은 대가로 명확함을 잃는다.
판단 기준은 예전 글에서 본 그 한 줄로 돌아간다 — “읽기 쉬움이 우선한다.” 왈러스가 중복을 없애고 의도를 또렷하게 하면 좋은 사용이고, 단지 줄 수를 줄이려고 흐름을 숨기면 나쁜 사용이다.
정리
왈러스 연산자 :=은 일반 대입 =과 달리 표현식이어서, 값을 대입하면서 동시에 그 값을 조건 검사나 다른 계산에 쓸 수 있다. while (line := f.readline()):처럼 읽기와 검사가 짝을 이루는 반복문, 그리고 컴프리헨션에서 무거운 계산을 한 번만 하고 재사용하는 경우에 특히 잘 어울린다. 반대로 평범한 대입을 굳이 표현식으로 위장하거나 한 식에 여러 번 끼워 넣어 흐름을 숨기는 것은 피해야 한다. 변수의 범위를 좁게 유지하면서 중복을 없애는 도구로 쓸 때, 왈러스는 코드를 더 파이썬답게 만든다.
언어의 본질과 설치에서 시작해 자료형과 제어문, 함수와 클래스, 모듈과 패키지, 파일과 예외, 이터레이터와 제너레이터, 동시성과 타입 힌트, 패키징과 테스트, 그리고 실무 라이브러리와 보안·함정까지 — 파이썬을 다루는 데 필요한 지형을 한 바퀴 돌았다. 각 주제의 공통된 교훈은 하나였다. “파이썬이 무엇을, 언제, 어떻게 처리하는가”를 정확히 이해하면, 대부분의 혼란은 예측 가능한 동작으로 바뀐다는 것이다. 그동안 함께해 주셔서 감사하다.
지난 글: 얕은 복사 vs 깊은 복사
읽어주셔서 감사합니다. 😊