betterway22변수위치인자사용

김승환·2021년 7월 11일

코딩의 기술

목록 보기
13/36

변수 위치 인자를 사용해 시각적인 잡음을 줄여라

  • 위치 인자를 가변적으로 받을 수 있으면 함수 호출이 더 깔끔해지고 시각적 잡음도 줄어든다.
  • 예를 들어 디버깅 정보를 로그에 남기고 싶다고 하자
  • 인자가 고정돼 있으면 메시지와 값의 list를 받는 함수가 필요하다.
def log(message, values):
    if not values:
        print(message)
    else:
        values_str = ', '.join(str(x) for x in values)
        print(f'{message}: {values_str}')

log('내 숫자는 ', [1, 2])
log('안녕 ', []) # 계속 []값을 넣어줘야하는 잡음

내 숫자는 : 1, 2
안녕

  • 로그에 남길 값이 없을 대도 빈 리스트를 넘겨야 한다면 귀찮을 뿐 아니라 코드 잡음도 많다.
  • 두번째 인자를 생략하면 좋다.
  • 파이썬에서는 마지막 위치 인자 이름 앞에 *을 붙이면 된다.
#
def log(message, *values):  # 달라진 유일한 부분
    if not values:
        print(message)
    else:
        values_str = ', '.join(str(x) for x in values)
        print(f'{message}: {values_str}')

log('내 숫자는 ', [1, 2])
log('안녕 ')  # 훨씬 좋다

내 숫자는 : [1, 2]
안녕

favorites = [7, 33, 99]
log('좋아하는 숫자는', *favorites)

좋아하는 숫자는: 7, 33, 99

가변적인 위치 인자를 받는 데는 두가지 문제점이 있다.

  • 첫번째 문제점은
    - 이런 선택적인 위치 인자가 함수에 전달되기 전에 항상 튜플로 반환된다는 것.
    - 이는 함수 호출 쪽에서 제너레이터 앞에 *연산자를 사용하면 제너레이터의 모든 원소를 얻기 위해 반복한다는 뜻이다.
    - 메모리 소비가 크다.
#
def my_generator():
    for i in range(10):
        yield i

def my_func(*args):
    print(args)
# 튜플로 반환되는 것을 볼수 있다.
# 제너레이터에서 반복이 이뤄졌다는 것을 알 수 있다.
it = my_generator()
my_func(*it)

(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

  • *args
  • 인자 목록에서 가변적인 부분에 들어가는 인자의 개수가 처리하기 좋을 정도로 충분히 작다는 사실을 알때 적합
  • 여러 리터럴이나 변수 이름을 함께 전달하는 함수 호출에 이상적
  • 주로 프로그래머의 편의와 코드 가독성을 위한 기능

- 두번째 문제점은

 - 함수에 새로운 위치 인자를 추가하면 해당 함수를 호출하는 모든 코드를 변경해야만 한다는 것
- 이미 가변 인자가 존재하는 함수 인자 목록의 앞부분에 위치 인자를 추가하려고 시도하면, 기존 호출 코드를 변경하지 않는 경우 미묘하게 깨질수 있음.
def log(sequence, message, *values):
    if not values:
        print(f'{sequence} - {message}')
    else:
        values_str = ', '.join(str(x) for x in values)
        print(f'{sequence} - {message}: {values_str}')

log(1, '좋아하는 숫자는', 7, 33)   # 새 코드에서 가변 인자를 사용. 문제 없음
log(1, '안녕')                   # 새 코드에서 가변 인자 없이 메시지만 사용. 문제 없음
log('좋아하는 숫자는', 7, 33)      # 예전 방식 코드는 깨짐

1 - 좋아하는 숫자는: 7, 33
1 - 안녕
좋아하는 숫자는 - 7: 33

  • 예외가 발생하지 않고 코드가 작동할 수도 있기 때문에 이런버그는 추적하기 어렵다.
  • 가능성을 완전히 없애려면 *args를 받아들이는 함수를 확장할 때는 키워드 기반의 인자만 사용해야 한다.
  • 방어적인 프로그래밍을 하려면 타입 애너테이션을 사용해도 된다.
profile
인공지능 파이팅!

0개의 댓글