본문 바로가기
코딩 연습/코딩배우기

파이썬 코딩의 기술 - 1.Pythonic #2

by good4me 2020. 12. 2.

goodthings4me.tistory.com

 

■ Effective_python1.Pythonic #2

05.복잡한 식 대신 도우미 함수 작성

from urllib.parse import parse_qs  ## query_string parsing

## 파라미터에서 값을 정수로 얻어야 하는 경우,

my_value = parse_qs('빨강=5&파랑=0&초록=', keep_blank_values=True)  ## dict 반환
print(repr(my_value))
# {'빨강': ['5'], '파랑': ['0'], '초록': ['']}

print('빨강', my_value.get('빨강'))  ## get()은 list 반환
# 빨강 ['5']
print('파랑', my_value.get('파랑'))
# 파랑 ['0']
print('투명도', my_value.get('투명도'))  ## get()은 값이 없으면 None 반환
# 투명도 None


## if 표현식 - [true] or [false]  왼쪽 식이 True이면 왼쪽, False면 오른쪽의 식 값 계산
red = my_value.get('빨강', [''])[0] or 0  ## True이면 index [0], False이면 0
print(f'빨강: {red!r}')  ## f-문자열 repr
# 빨강: '5'
opacity = my_value.get('투명도', [''])[0] or 0
print(f'투명도: {opacity!r}')  ## get()은 키가 없을 때 두번째 인자 반환
# 투명도: 0


## 파라미터 정수를 얻기
red = int(my_value.get('빨강',[''])[0] or 0)
print(red)
# 5


## 파라미터가 많은 경우, 로직 반복(중복)이 많아진다.
## 식이 복잡해지면 식을 더 작은 조각으로 나눠서 로직을 도우미 함수로 할지 고민하는 것이 좋으며,
## 이유는, 코드를 줄여쓰는 것보다 가독성을 좋게 하는 것이 가치가 있다.

def get_first_int(value, key, default=0):
    found = value.get(key, [''])
    if found[0]:
        return int(found[0])
    return default


print(get_first_int(my_value, '빨강'))
# 5
print(get_first_int(my_value, '파랑'))
# 0
print(get_first_int(my_value, '초록'))
# 0
print(f"투명도: {get_first_int(my_value, '투명도')}")
red_str = my_value.get('빨강', [''])
red = red_str[0] if red_str[0] else 0  # 삼항 조건식
print(red)
# 5

good4me.co.kr

 

06.인덱스 대신 언패킹(풀기) 대입 방법 사용

item = ('호박엿', '식혜')
first = item[0]
second = item[1]
print(first, '&', second)  ## index 사용 출력
# 호박엿 & 식혜

first, second = item  ## 언패킹 사용
print(first, '&', second)
# 호박엿 & 식혜

## 리스트 요소에 index 통해 접근
snacks = [('베이컨', 358), ('도넛', 240), ('머핀', 190)]
for i in range(len(snacks)):
    item = snacks[i]
    name = item[0]
    calories = item[1]
    print(f'#{i + 1}: {name}은 {calories}칼로리입니다.')

#1: 베이컨은 358칼로리입니다.
#2: 도넛은 240칼로리입니다.
#3: 머핀은 190칼로리입니다.

## 내장함수(enumerate)와 언패킹 사용 시, 리스트 요소에 쉽게 접근
for rank, (name, calories) in enumerate(snacks, 1):
    print(f'#{rank}: {name}은 {calories}칼로리입니다.')

#1: 베이컨은 358칼로리입니다.
#2: 도넛은 240칼로리입니다.
#3: 머핀은 190칼로리입니다.

 

 

07.range보다는 enumertate 사용

## 리스트 이터레이션 시 몇 번째 요소 처리중인지 알아야 할 때

flavor_list = ['바닐라', '초콜릿', '딸기', '아이스크림']
for i in range(len(flavor_list)):
    flavor = flavor_list[i]
    print(f'{i + 1}: {flavor}')

# 1: 바닐라
# 2: 초콜릿
# 3: 딸기
# 4: 아이스크림


for i, flavor in enumerate(flavor_list):
    print(f'{i + 1}: {flavor}')

# 1: 바닐라
# 2: 초콜릿
# 3: 딸기
# 4: 아이스크림


## enumerate 동작 방식
it = enumerate(flavor_list)
print(next(it))
print(next(it))
# (0, '바닐라')
# (1, '초콜릿')

 

 

08.여러 이터레이터 루프 수행 시 zip 사용

names = ['사과', '바나나', '감', '파인애플']
counts = [len(n) for n in names]
print(counts)
# [2, 3, 1, 4]

longest_name = None
max_count = 0

for i in range(len(names)):
    count = counts[i]
    if count > max_count:
        longest_name = names[i]
        max_count = count

print(longest_name)
# 파인애플

## zip은 둘 이상의 이터레이터를 지연 계산 제너레이터를 사용해 묶어준다
## 단, 이터레이터의 길이가 같아야 한다(zip은 짧은 길이를 기준으로 처리)
for name, count in zip(names, counts):
    if count > max_count:
        longest_name = name
        max_count = count

print(longest_name)
# 파인애플


## 길이가 다른 이터레이터를 zip에 전달 --> itertools.zip_longest 사용
## 존재하지 않는 값은 fillvalue(default는 None)로 대체
names.append('망고')
import itertools
for name, count in itertools.zip_longest(names, counts):
    print(f'{name}: {count}')

# 사과: 2
# 바나나: 3
# 감: 1
# 파인애플: 4
# 망고: None

 

 

09.반복문(for, while) 뒤에 else 블록 사용하지 않기

 

10.대입식(assignment expression)으로 반복 피하기

  • 대입식(assignment expression) - 왈러스 연산자(walrus operator) : 3.8에서 도입
  • a := b  --> a 왈러스 b, := 기호는 바다코끼리의 눈과 엄니
  • 대입식의 값은 왈러스 연산자 왼쪽에 있는 식별자에 대입된 값
  • 대입문이 쓰일 수 없는 위치에서 변수에 값을 대입할 수 있어서 유용함
fresh_fruit = {
    '사과': 10,
    '바나나': 8,
    '레몬': 5,
}

def out_of_stock(count):
    print(f'{count}개')

count = fresh_fruit.get('레몬', 0)

if count:
    out_of_stock(count)
else:
    print('재고 없음')

# 5개

## 한 번만 쓰이는 변수(중요하지 않은 변수)를 대입식으로 처리 (대입 후 평가)
if count := fresh_fruit.get('사과', 0):  ## if문에서만 사용하는 변수 의미
    out_of_stock(count)
else:
    print('재고 없음')

# 10개

## 주의사항  : 대입식 결과와 비교연산자가 있을 경우 대입식을 괄호로 감싼다
if count := fresh_fruit.get('레몬', 0) >= 5:
    out_of_stock(count)
else:
    print('재고 없음')
    
# True개

if (count := fresh_fruit.get('레몬', 0)) >= 5:
    out_of_stock(count)
else:
    print('재고 없음')

# 재고 없음

 

 

댓글