1. 대입식
대입식은 영어로 assignment expression이며 왈러스 연산자(walrus operator)라고도 부른다. 이 대입식은 파이썬 언어에서 고질적인 중복 문제를 해결하고자 파이썬 3.8에서 새롭게 도입된 구문이다.
일반 대입문은 a = b라고 쓰며 'a 이퀄(equal) b'라고 읽지만, 왈러스 연산자는 a := b라고 쓰며 'a 왈러스 b'라고 읽는다.
대입식은 대입문이 쓰일 수 없는 위치에서 변수에 값을 대입할 수 있으므로 유용하다. 예를 들어 if 문의 조건식 안에서 대입식을 쓸 수 있다. 대입식의 값은 왈러스 연산자 왼쪽에 있는 식별자에 대입된 값으로 평가된다.
2. 예제
2-1. 레모네이드
다음은 주스 바에서 사용할 신선한 과일 바구니를 관리하는 예제이다.
fresh_fruit = {
'사과': 10,
'바나나': 8,
'레몬': 5,
}
고객이 레모네이드를 주문했다면 과즙을 낼 레몬이 과일 바구니에 최소 하나는 있어야 한다. 다음은 레몬의 개수를 읽어와서 그 값이 0이 아닌지 검사하는 코드다.
def make_lemonade(count):
...
def out_of_stock():
...
count = fresh_fruit.get('레몬', 0)
if count:
make_lemonade(count)
else:
out_of_stock()
간단해 보이지만 문제점이 있다. count 변수는 if 문의 첫번째 블록 안에서만 쓰인다. if 앞에서 count를 정의하면 else 블록이나 그 이후의 코드에서 count 변수에 접근해야 할 필요가 있는 것처럼 보이기 때문에 실제보다 변수가 중요해 보인다. 하지만 그렇지 않다.
파이썬에서는 이런 식으로 값을 가져와서 그 값이 0이 아닌지 검사한 후 사용하는 패턴이 자주 발생하는데, 왈러스 연산자를 통해 위 문제를 해결할 수 있다.
if count := fresh_fruit.get('레몬', 0):
make_lemonade(count)
else:
out_of_stock()
한 줄 더 짧기도 하지만, count가 if 문의 첫 번재 블록에서만 의미가 있다는 점이 명확히 보이기 때문에 이 코드가 더 읽기 쉽다. 대입 연산자는 우선 count 변수에 값을 대입하고, if 문의 맥락에서 대입된 값을 평가해 프로그램 흐름을 어떻게 제어할지 판단한다. 이런 두 단계의 동작(대입 후 평가)이 왈러스 연산자의 핵심이다.
2-2. 사과주스
또 다른 예시이다. 레몬은 하나면 충분하지만 사과 주스에서는 사과가 최소 4개는 필요하다.
def make_cider(count):
...
count = fresh_fruit.gert('사과', 0)
if count >= 4:
make_cider(count)
else:
out_of_stock()
이 코드도 레모네이드 예제와 마찬가지로 count 대입이 변수를 쓸데없이 너무 강조하여 왈러스 연산자를 통해 더 명확하게 쓸 수 있다.
if (count := fresh_fruit.get('사과', 0)) >= 4:
make_cider(count)
else:
out_of_stock()
2-3. 바나나 스무디
스무디를 만들려면 바나나 슬라이스가 최소 두 개는 필요하고, 슬라이스가 부족하면 OutOfBananas 예외를 발생시켜야 한다. 전형적인 방식은 다음과 같다.
def slice_bananas(count):
...
class OutOfBananas(Exception):
pass
def make_smoothies(count):
...
pieces = 0
count = fresh_fruit.get('바나나', 0)
if count >= 2:
pieces = slice_bananas(count)
try:
smoothies = make_smoothies(pieces)
except OutOfBanans:
out_of_stock()
로직을 수행하는 다른 방식은 pieces = 0 대입문을 else 블록에 넣는 것이다.
count = fresh_fruit.get('바나나', 0)
if count >= 2:
pieces = slice_bananas(count)
else:
pieces = 0
try:
smoothies = make_smoothies(pieces)
except OutOfBananas:
out_of_stock()
다음처럼 왈러스 연산자를 사용하면 count 변수가 더 이상 강조되지 않는다.
pieces = 0
if (count := fresh_fruit.get('바나나', 0)) >= 2:
pieces = slice_bananas(count)
try:
smoothies = make_smoothies(pieces)
except: OutOfBananas:
out_of_stock()
왈러스 연산자를 사용하면 pieces를 if 문의 두 부분에 나눠서 정의하는 코드의 가독성도 좋아진다.
if (count := fresh_fruit.get('바나나', 0)) >= 2:
pieces = slice_bananas(count)
else:
pieces = 0
try:
smoothies = make_smoothies(pieces)
except OutOfBananas:
out_of_stock()
2-4 바나나 스무디, 애플 주스, 레모네이드 순으로 제공하기
파이썬에는 switch/case 문이 없어서 다음과 같이 if/else 구문을 늘이는 경우가 허다하다.
count = fresh_fruit.get('바나나', 0)
if count >= 2:
pieces = slice_bananas(count)
to_enjoy = make_smoothies(pieces)
else:
count = fresh_fruit.get('사과', 0)
if count >= 4:
to_enjoy = make_cider(count)
else:
count = fresh_fruit.get('레몬', 0)
if count:
to_enjoy = make_lemonade(count)
else:
to_enjoy = '아무것도 없음'
왈러스 연산자를 사용하면 좀 더 우아하게 만들 수 있다.
if (count := fresh_fruit.get('바나나', 0)) >= 2:
pieces = slice_bananas(count)
to_enjoy = make_smoothies(pieces)
elif (count := fresh_fruit.get('사과', 0)) >= 4:
to_enjoy = make_cider(count)
elif count := fresh_fruit.get('레몬', 0):
to_enjoy = make_lemonade(count)
else:
to_enjoy = '아무것도 없음'
2-5. 신선한 과일이 배달돼서 이 과일을 모두 주스로 만든 후 병에 담는 경우
do/while 루프 의 경우도 비슷한 경우로 파이썬에 없다. 따라서 다음은 while 루프로 구현된 코드다.
def pick_fruit():
...
def make_juice(fruit, count):
...
bottles = []
fresh_fruit = pick_fruit()
while fresh_fruit:
for fruit, count in fresh_fruit.items():
batch = make_juice(fruit, count)
bottles.extend(batch)
fresh_fruit = pick_fruit()
이 코드는 fresh_fruit = pick_fruit()를 2번하므로 반복적이다. 이를 해결하기 위해서는 중간에서 break 문을 사용하는 것이다.
bottles = []
while True: # 무한 루프
fresh_fruit = pick_fruit()
if not fresh_fruit: # 중간에서 끝내기
break
for fruit, count in fresh.items():
batch = make_juice(fruit, count)
bottles.extend(batch)
왈러스 연산자를 사용하면 while 루프에서 매번 fresh_fruit 변수에 대입하고 조건을 검사할 수 있으므로 더욱 우아한 코드가 된다.
bottles = []
while fresh_fruit := pick_fruit():
for fruit, count in fresh_fruit.items():
batch = make_juice(fruit, count)
bottles.extend(batch)
3. 기억해야 할 내용
- 대입식에서는 왈러스 연산자(:=)를 사용해 하나의 식 안에서 변수 이름에 값을 대입하면서 이 값을 평가할 수 있고, 중복을 줄일 수 있다.
- 대입식이 더 큰 식의 일부분으로 쓰일 떄는 괄호로 둘러싸야 한다.
- 파이썬에서는 switch/case 문이나 do/while 루프를 쓸 수 없지만, 대입식을 사용하면 이런 기능을 더 깔끔하게 흉내 낼 수 있다.
'언어 > 파이썬' 카테고리의 다른 글
[Effective Python] BETTER WAY 13 - 슬라이싱보다는 나머지를 모두 잡아내는 언패킹을 사용하라 (0) | 2023.01.04 |
---|---|
[Effective Python] BETTER WAY 9 - for나 while 루프 뒤에 else 블록을 사용하지 말라 (0) | 2022.12.31 |
[Effective Python] BETTER WAY 7 - range보다는 enumerate를 사용하라 (0) | 2022.12.29 |
[Effective Python] BETTER WAY 6 - 인덱스를 사용하는 대신 대입을 사용해 데이터를 언패킹해라 (0) | 2022.12.29 |
[Effective Python] BETTER WAY 5 - 복잡한 식을 쓰는 대신 도우미 함수를 작성하라 (0) | 2022.12.28 |