python3.8에서 도입된 Assignment expression, 왈러스 연산자 라고도 부른다.
일반 대입문은 a = b
왈러스 연산자는 a := b
대입문을 쓸수 없는 위치에서 변수에 값을 대입할 수 있음
fresh_fruit = {
'사과': 10,
'바나나': 8,
'레몬': 5,
}
def make_lemnonade(count):
pass
def out_of_stock():
pass
count = fresh_fruit.get('레몬', 0)
if count:
make_lemnonade(count)
else:
out_of_stock()
count 변수는 if 문의 첫번째 블록에서만 사용됨
이처럼 파이썬에서는 값을 가져와서 그 값이 0이 아닌지 검사한 후 사용하는 패턴이 자주 발생
이를 위해 가독성이 떨어지는 꼼수를 사용했지만 대입식을 이용하면 해결이 된다.
if count := fresh_fruit.get('레몬', 0):
make_lemnonade(count)
else:
out_of_stock()
대입 후 평가가 왈러스 연산자의 핵심
def make_cider(count):
print('make_cider')
count = fresh_fruit.get('사과', 0)
if count >= 4:
make_cider(count)
else:
out_of_stock()
if (count := fresh_fruit.get('사과', 0)) >= 4:
make_cider(count)
else:
out_of_stock()
make_cider
대입 결과와 4를 비교하기 위해 대입식을 괄호로 둘러싸야 한다.
둘러싸지 않을 경우 비교가 먼저 되고 그 값이 count에 대입된다.
if (count := fresh_fruit.get('사과', 0)) >= 4:
print(count)
make_cider(count)
else:
out_of_stock()
10 make_cider
if count := fresh_fruit.get('사과', 0) >= 4:
print(count)
make_cider(count)
else:
out_of_stock()
True make_cider
조건에 따라 현재 위치를 둘러싸는 영역에 있는 변수에 값을 대입하고 그 변수를 바로 함수 호출에 사용하는 경우를 들 수 있다.
def slice_bananas(count):
print('slice bananas')
class OutOfBananas(Exception):
pass
def make_smoothies(count):
print('make smoothies')
prices = 0
count = fresh_fruit.get('바나나', 0)
if count >= 2:
pieces = slice_bananas(count)
try:
smoothies = make_smoothies(pieces)
except OutOfBananas:
out_of_stock()
slice bananas make smoothies
로직을 수행하는 다른 방식은 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()
slice bananas make smoothies
대부분 첫번째를 선호한다.
왈러스 연산자를 이용해보자
pieces = 0
if (count := fresh_fruit.get('바나나', 0)) >= 2:
pieces = slice_bananas(count)
try:
smoothies = make_smoothies(pieces)
except OutOfBananas:
out_of_stock()
slice bananas make smoothies
if (count := fresh_fruit.get('바나나', 0)) >= 2:
pieces = slice_bananas(count)
else:
pieces = 0
try:
smoothies = make_smoothies(pieces)
except OutOfBananas:
out_of_stock()
slice bananas make smoothies
파이썬에는 유연한 switch/case 문이 없다
대신 if, elif, 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 = '아무것도 없음'
slice bananas make smoothies
왈러스 연산자를 이용해보자
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 = '아무것도 없음'
slice bananas make smoothies
do/while 루프가 없다는 점도 당황스럽다.
import random
def pick_fruit():
if random.randint(1,10) > 2: # 80% 확률로 새 과일 보충
return {
'사과': random.randint(0,10),
'바나나': random.randint(0,10),
'레몬': random.randint(0,10),
}
else:
return None
def make_juice(fruit, count):
if fruit == '사과':
return [('사과주스', count/4)]
elif fruit == '바나나':
return [('바나나스무디',count/2)]
elif fruit == '레몬':
return [('레모네이드',count/1)]
else:
return []
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()
print(bottles)
[('사과주스', 1.5), ('바나나스무디', 4.5), ('레모네이드', 0.0)]
이 코드는 fresh_fruit = pick_fruit() 호출을 두 번 (한번은 루프 직전에 초기화) 호출하고, 다른 한번은 루프의 끝에서 사용한다.
코드 재사용을 향상시키기 위한 전략은 무한 루프-중간에서 끝내기(loop-and-a-half) 관용어를 사용하는 것이다.
이 관용어를 사용하면 코드 반복을 없앨 수 있지만, while 루프를 맹목적인 무한 루프로 만들기 때문에 while 루프의 유용성이 줄어든다.
bottles = []
while True: # 무한루프
fresh_fruit = pick_fruit()
if not fresh_fruit: # 중간에서 끝내기
break
for fruit, count in fresh_fruit.items():
batch = make_juice(fruit, count)
bottles.extend(batch)
print(bottles)
[('사과주스', 1.75), ('바나나스무디', 4.5), ('레모네이드', 4.0), ('사과주스', 1.5), ('바나나스무디', 3.5), ('레모네이드', 2.0), ('사과주스', 0.25), ('바나나스무디', 1.5), ('레모네이드', 7.0), ('사과주스', 0.0), ('바나나스무디', 2.5), ('레모네이드', 1.0)]
왈러스 연산자를 사용하면 while 루프에서 매번 fresh_fruit 변수에 대입하고 조건을 감사할 수 있다.
bottles = []
while fresh_fruit := pick_fruit():
for fruit, count in fresh_fruit.items():
batch = make_juice(fruit, count)
bottles.extend(batch)
print(bottles)
[('사과주스', 2.25), ('바나나스무디', 1.5), ('레모네이드', 3.0), ('사과주스', 0.25), ('바나나스무디', 3.0), ('레모네이드', 4.0), ('사과주스', 1.5), ('바나나스무디', 1.5), ('레모네이드', 8.0), ('사과주스', 1.5), ('바나나스무디', 2.0), ('레모네이드', 1.0), ('사과주스', 0.75), ('바나나스무디', 0.5), ('레모네이드', 5.0), ('사과주스', 1.0), ('바나나스무디', 4.5), ('레모네이드', 7.0)]