:= assignment expression

참고자료


소개

:= 대입 연산자를 walrus operator라고 부른다. walrus는 바다코끼리를 뜻하는데 :=이 마치 바다코끼리의 눈과 엄니를 닮아서라고 한다. 정식 명칭은 assignment expression이다.

pixabay/OpenClipart-Vectors

Gopher라면 익숙할 이 대입 연산자는 코드를 간결하게 만들어준다. 다만 Python 3.8에서 도입된 연산자이므로 사용 시 버전에 유의해야 한다. 

# Without :=
match = pattern.search(data)
if match is not None:
    print(f"matched pattern: {match}")

# With :=
if (match := pattern.search(data)) is not None:
    print(f"matched pattern: {match}")

:=를 활용하면 다양한 곳에서 변수 대입이 가능해진다. 파이썬의 창시자인 Tim은 위와 같이 한 줄에서 많은 처리가 일어나는 '바쁜' 코드를 선호하지 않는다고 밝혔다. 하지만 아래 예시와 같은 경우, := 연산자가 일반 대입 연산보다 편리함을 인정했다. 

# Old
while True:
    d = x // a**(n-1)
    if a <= d:
        break
    a = ((n-1)*a + d) // n
return a

# New
while a > (d := x // a**(n-1)):
    a = ((n-1)*a + d) // n
return a

코드가 훨씬 간결해진 것을 볼 수 있다. 이처럼 :=는 코드의 가독성을 높여줄 수 있다.


대입문과의 차이

x = y = z = 0 # x, y, z: (0, 0, 0)
(z := (y := (x := 0))) # x, y, z: (0, 0, 0)

x = 1, 2  # x: (1, 2)
(x := 1, 2)  # x: 1

loc = x, y
loc := (x, y)

info = name, phone, *rest
info := (name, phone, *rest)

일반적으로 대입에 사용되는 =과 동일하게 사용할 수는 없다. 특히 ( )를 이용한 범위, 우선순위 지정이 중요하다. 

  • 괄호 없이는 여러 값을 대입할 수 없다.
  • 대입되는 우선순위가 다르다.
  • packing, unpacking을 수행하기 위해서는 괄호로 대입 우선순위를 정해주어야 한다. 

사용 예시

아래 예시들이 반드시 '좋은' 코드라는 것은 아니다. 상황에 따라, 사람에 따라 선호하는 코드가 다를 수 있다. 다만 := 연산자의 다양한 사용 방법을 보여주고자 작성하였다. 

 

1. 형식이 다른 #Tag 찾기

lines = ["#aa", " #bb", " *cc", "#dd"]

# Old
only_tags = True
for line in lines:
    tag = line.lstrip()
    if not tag.startswith('#'):
        print(f"`{tag}` is not a tag")
        only_tags = False
        break
if only_tags:
    print("All lines are tags")

# New
if all((tag := line.lstrip()).startswith('#') for line in lines):
    print("All lines are tags")
else:
    print(f"`{tag}` is not a tag")
    
# Output: `*cc` is not a tag

for-if문 대신 all를 이용해 코드를 축약할 수 있다. 참고로 all은 iterable 객체가 조건을 모두 만족할 경우, True를 반환하는 함수이다. 

 

2. 입력 끝까지 읽어오기

# Old
while True:
    line = stdin.readline()
    if line is None:
        break        
    print(line)

# New
while line := stdin.readline():
    print(line)

위에서도 봤듯 while True: if ~ break 형식의 조건 반복문을 훨씬 간결하게 작성할 수 있다. 

 

3. 제곱 값 계산하기

# Old
ys = [(f(x), f(x)**2, f(x)**3) for x in inputs]

# New
ys = [(y := f(x), y**2, y**3) for x in inputs]

#Old의 경우 f(x)(하나의 x에 대해) 3번 실행하게 된다. 반면 :=를 활용하면 한 번의 실행으로 연산에 사용되는 비용을 줄일 수 있다.