본문으로 건너뛰기
개발 머꼬
개발 노트Python
hohyeon.dev31

walrus 연산자(:=)로 만든 변수가 컴프리헨션 밖에서도 보인 이유

  • #Engineering Note
  • #Python

문제 발생

리스트 컴프리헨션 안에서 :=(walrus 연산자, 대입 표현식)로 중간 계산값을 저장했는데, 그 변수가 컴프리헨션이 끝난 뒤에도 바깥 스코프에 남아있어서 의도치 않게 다른 변수를 덮어썼습니다.

results = [y for x in data if (y := expensive_calc(x)) > 0]
print(y)  # 컴프리헨션이 끝났는데도 마지막으로 계산된 y 값이 그대로 출력됨

원인 분석

Python 3.8에서 도입된 walrus 연산자(:=)는 표현식 안에서 값을 계산하면서 동시에 변수에 대입할 수 있게 해줍니다. 리스트 컴프리헨션의 일반 for 루프 변수(for x in datax)는 컴프리헨션 자신만의 격리된 스코프에 속해서 바깥으로 새어나가지 않지만, walrus 연산자로 만든 변수는 의도적으로 예외입니다 — PEP 572(walrus 연산자를 도입한 제안서)는 :=로 만든 변수가 그 컴프리헨션을 감싸고 있는 바깥 함수(또는 모듈) 스코프에 귀속되도록 명시적으로 설계했습니다.

이건 버그가 아니라 의도된 설계입니다 — walrus 연산자가 처음 만들어진 목적 자체가 "컴프리헨션 안에서 계산한 중간값을 밖에서도 재사용하고 싶다"는 요구를 충족하기 위한 것이었습니다(예: 필터링에 쓴 계산 결과를 다시 계산하지 않고 그대로 쓰고 싶은 경우).

해결 방안

  1. 이 동작을 알고 의도적으로 활용할 수 있습니다 — 컴프리헨션에서 계산한 값을 이후 로직에서 재사용해야 한다면 정확히 이 특성이 유용합니다.
  2. 의도치 않은 변수 덮어쓰기가 걱정된다면, walrus 연산자로 만드는 변수 이름을 그 스코프의 다른 어떤 변수와도 겹치지 않는, 명확히 구분되는 이름으로 짓습니다.
  3. 컴프리헨션 자체가 여러 줄에 걸쳐 복잡한 조건과 walrus 연산자를 섞어 쓰기 시작하면 가독성이 떨어지는 신호입니다 — 그 시점에는 일반 for 루프로 풀어써서 각 단계를 명시적인 변수로 표현하는 것이 오히려 더 명확할 수 있습니다.
  4. 제네레이터 표현식에서도 동일한 스코프 규칙이 적용됩니다 — 리스트 컴프리헨션에 국한된 특성이 아닙니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.