파이썬에서 복잡한 식 대신 도우미 함수를 쓰는 이유

Sue·2025년 8월 7일
0

Effective Python

목록 보기
7/9
post-thumbnail

이 항목의 핵심 메시지는 "코드는 간결함보다 명료함이 우선"이라는 것입니다. 한 줄로 복잡한 로직을 표현하려는 시도는 종종 가독성을 해치고, 잠재적인 버그를 만들어내기 쉽습니다. 이럴 때 잘 명명된 도우미 함수(Helper Function)를 사용하는 것이 훨씬 효과적인 방법입니다.

코드 분석을 통한 단계별 학습

1. 문제 상황: URL 쿼리 파라미터 처리

먼저, 코드가 어떤 문제를 해결하려 하는지 이해해야 합니다.

urllib.parse.parse_qs 함수는 URL의 쿼리 문자열(예: ?name=value&...)을 파싱하여 딕셔너리로 만들어 줍니다.

from urllib.parse import parse_qs

my_values = parse_qs('빨강=5&파랑=0&초록=',
                     keep_blank_values=True)
print(repr(my_values))
# 출력 결과: {'빨강': ['5'], '파랑': ['0'], '초록': ['']}

여기서 중요한 점은 parse_qs의 결과입니다.

  • 모든 값은 리스트에 담겨 있습니다. (예: '5'가 아닌 ['5'])
  • 값이 없는 키(초록=)는 빈 문자열을 담은 리스트([''])가 됩니다.
  • 쿼리에 없는 키(예: 투명도)에 접근하려고 하면 에러가 발생하므로 .get() 메서드를 사용해야 합니다.

우리가 하려는 작업은 이 딕셔너리에서 각 색상 값을 정수(integer)형으로 안전하게 가져오는 것입니다.

2. 나쁜 접근 방식: 복잡한 한 줄 표현식

이 문제를 해결하기 위해 다음과 같은 복잡한 한 줄 코드를 사용할 수 있습니다.

# 'or' 트릭을 이용한 복잡한 식
red = my_values.get('빨강', [''])[0] or 0
green = my_values.get('파랑', [''])[0] or 0 # 의도와 다른 키('파랑')를 사용하는 실수
opacity = my_values.get('투명도', [''])[0] or 0

print(f'빨강: {red!r}')     # 출력: '5' (문자열)
print(f'초록: {green!r}')   # 출력: '0' (문자열)
print(f'투명도: {opacity!r}') # 출력: 0   (정수)

이 코드의 문제점:

  1. 가독성이 매우 낮습니다: .get()의 기본값, 리스트 인덱싱(''), 그리고 or 연산자의 단락 평가(short-circuit) 원리까지 한 번에 이해해야 합니다. 코드를 처음 보는 사람은 의도를 파악하기 어렵습니다.
  2. 잠재적 버그:
    • red의 값은 문자열 '5'이지만, opacity의 값은 정수 0입니다. 이렇게 반환 타입이 일관되지 않으면 나중에 타입 관련 버그(TypeError)를 유발할 수 있습니다.
    • 코드가 복잡하다 보니 복사-붙여넣기 과정에서 green 변수에 파랑 키를 사용하는 실수가 발생했습니다. 코드가 명료했다면 이런 실수를 더 쉽게 발견했을 것입니다.

3. 조금 나은 접근 방식: 조건부 표현식

위 문제를 해결하기 위해 코드를 조금 더 풀어쓰면 가독성이 약간 향상됩니다.

# if/else 조건부 표현식 사용
red_str = my_values.get('빨강', [''])
red = int(red_str[0]) if red_str[0] else 0

이 코드는 or 트릭보다는 의도가 명확합니다. "문자열이 존재하면 정수로 바꾸고, 그렇지 않으면 0으로 설정하라"는 의미를 더 쉽게 읽을 수 있습니다.

하지만 여전히 문제입니다. 만약 파라미터를 10개 처리해야 한다면, 이 두 줄짜리 로직을 10번 반복해야 합니다. 이는 코드 중복을 야기하며, 나중에 로직을 수정해야 할 때 10곳을 모두 고쳐야 하는 유지보수의 어려움을 만듭니다.

4. 가장 좋은 해결책: 도우미 함수 작성

이 모든 문제를 해결하는 가장 좋은 방법은 로직을 도우미 함수로 분리하는 것입니다.

def get_first_int(values, key, default=0):
    found = values.get(key, [''])
    if found[0]:
        # 값이 존재하면 정수로 변환하여 반환
        return int(found[0])
    # 키가 없거나 값이 비어있으면 기본값 반환
    return default

# 도우미 함수 사용
green = get_first_int(my_values, '초록')
red = get_first_int(my_values, '빨강')
opacity = get_first_int(my_values, '투명도')

print(f'초록: {green}')     # 출력: 0
print(f'빨강: {red}')       # 출력: 5
print(f'투명도: {opacity}') # 출력: 0

도우미 함수의 장점:

  1. 가독성 (Readability): get_first_int(my_values, '초록')이라는 코드만 봐도 "my_values에서 '초록' 키에 해당하는 첫 번째 값을 정수로 가져온다"는 의도가 명확하게 드러납니다.
  2. 재사용성 (Reusability): 동일한 로직이 필요한 모든 곳에서 이 함수를 호출하기만 하면 됩니다. 코드 중복이 사라집니다 (DRY: Don't Repeat Yourself 원칙).
  3. 유지보수성 (Maintainability): 만약 파라미터 값이 숫자가 아닐 경우를 대비해 예외 처리(try-except ValueError)를 추가하고 싶다면, 함수 내부만 한 번 수정하면 이 함수를 사용하는 모든 곳에 적용됩니다.
  4. 견고함 (Robustness): 함수 내에서 모든 엣지 케이스(키가 없는 경우, 값이 비어있는 경우)를 처리하므로 사용자는 안심하고 함수를 호출할 수 있습니다.

최종 정리

복잡한 로직을 한 줄의 표현식으로 압축하려는 유혹을 피해야 합니다.

대신, 로직의 의도를 명확히 설명하는 이름의 도우미 함수를 작성하세요.

이렇게 하면 코드가 더 명료해지고, 재사용하기 쉬워지며, 미래에 수정하기도 훨씬 수월해집니다. 이는 파이썬다운 코드를 작성하는 중요한 원칙 중 하나입니다.

profile
AI/ML Engineer

0개의 댓글