Python * 문법 완벽 가이드: 함수 인자, 언패킹, 가변 인자까지

Python에서 *는 다양한 용도로 사용되어, 각각의 의미와 쓰임을 알면 코드를 더욱 유연하고 효율적으로 작성할 수 있습니다. 이번 글에서는 *의 역할과 사용 예제를 통해 Python의 * 문법을 확실히 이해할 수 있도록 도와드리겠습니다.


1. *로 가변 인자 (*args) 받기

가장 흔하게 사용하는 *의 용도는 함수의 가변 인자를 받는 것입니다. *args를 사용하면 함수가 임의의 개수의 인자를 받을 수 있게 되어, 코드의 유연성이 높아집니다.

def print_all(*args):
    for arg in args:
        print(arg)

# 실행 예시
print_all(1, 2, 3)
print_all("apple", "banana", "cherry")

설명

  • *args튜플 형태로 전달되며, 함수에서 여러 개의 인자를 하나의 변수로 받아 처리할 수 있게 합니다.
  • 인자의 개수가 정해지지 않았거나 동적으로 처리해야 할 때 유용합니다.

2. *로 리스트나 튜플 언패킹하기

*리스트나 튜플을 언패킹하여 각각의 요소를 별도의 값으로 전달할 때도 사용됩니다. 이 문법을 통해 리스트나 튜플의 각 요소를 개별 인자로 분리하여 함수에 전달할 수 있습니다.

def add(a, b, c):
    return a + b + c

numbers = [1, 2, 3]
result = add(*numbers)  # 리스트를 언패킹하여 각각의 요소를 인자로 전달
print(result)

설명

  • *numbers는 리스트 [1, 2, 3]언패킹하여 각각의 요소를 함수 add에 인자로 전달합니다.
  • 리스트나 튜플의 요소 개수와 함수의 인자 개수가 일치해야 합니다. 일치하지 않으면 오류가 발생합니다.

3. 함수에서 *로 위치 기반 인자와 키워드 인자 구분하기

함수 정의 시 *를 사용해 위치 기반 인자와 키워드 인자 사이를 구분할 수 있습니다. 위치 인자와 키워드 인자를 명확하게 구분하여 함수 호출 시 오류를 방지하고 가독성을 높입니다.

def order_items(main, *sides, drink):
    print(f"Main dish: {main}")
    print("Side dishes:", sides)
    print(f"Drink: {drink}")

# 실행 예시
order_items("Burger", "Fries", "Salad", drink="Cola")

설명

  • *sides가변 위치 인자를 받아 튜플 형태로 저장합니다.
  • drink키워드 인자로만 전달할 수 있습니다. 즉, drink="Cola"처럼 키워드로 명시해야 합니다.
  • 이 방식을 사용하면 특정 인자를 명시적으로 키워드 인자로만 전달하게 할 수 있어, 코드의 가독성과 유지보수성이 높아집니다.

4. *로 리스트나 튜플 결합하기

Python의 * 문법은 리스트나 튜플을 결합할 때도 사용할 수 있습니다. 여러 리스트를 결합하거나, 리스트에 요소를 추가할 때 유용하게 사용할 수 있습니다.

list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined_list = [*list1, *list2]  # 리스트 결합

print(combined_list)

설명

  • [ *list1, *list2 ]list1list2를 각각 언패킹하여 하나의 리스트로 결합합니다.
  • 같은 방식으로 튜플을 결합할 수 있으며, 코드가 간결해지고 가독성이 높아집니다.

5. *로 여러 개의 값을 한 변수에 묶기

반대로, *를 사용하여 여러 개의 값을 한 변수에 묶어 저장할 수도 있습니다. 함수의 매개변수에서 일부 값을 개별 변수로 할당하고, 나머지 값을 리스트로 묶어 관리할 때 유용합니다.

def split_elements(first, *rest):
    print("First element:", first)
    print("Remaining elements:", rest)

# 실행 예시
split_elements(1, 2, 3, 4, 5)

설명

  • 첫 번째 인자는 first에 저장되고, 나머지 인자는 *rest묶여서 튜플 형태로 저장됩니다.
  • 이러한 방식은 함수 인자 중 특정 인자만 분리하고 나머지를 한꺼번에 관리할 때 유용하게 사용됩니다.

6. 딕셔너리 언패킹으로 ** 대신 * 사용하기

*딕셔너리를 언패킹하는 데도 사용할 수 있지만, 값만 가져오며 키는 무시됩니다. 딕셔너리에서 모든 값만 필요할 때 유용합니다.

data = {'a': 1, 'b': 2, 'c': 3}
print(*data)  # 'a', 'b', 'c' 키만 가져옴
print(*data.values())  # 값들만 출력: 1 2 3

설명

  • *data는 딕셔너리의 키만 출력하고, *data.values()는 딕셔너리의 값을 개별 인자로 언패킹합니다.
  • 딕셔너리의 키나 값만 가져올 때 * 문법을 활용하면 반복문 없이도 값에 쉽게 접근할 수 있습니다.

요약: Python에서 * 문법 정리

Python의 *는 다음과 같이 여러 방식으로 사용됩니다.

  1. 함수에서 가변 인자를 받을 때 (*args)
  2. 리스트나 튜플을 언패킹하여 함수에 인자로 전달할 때
  3. 함수 정의에서 위치 인자와 키워드 인자를 구분할 때
  4. 여러 리스트나 튜플을 결합할 때
  5. 함수 매개변수에서 여러 값을 한 변수에 묶을 때
  6. 딕셔너리의 값만 언패킹할 때

이처럼 *는 다양한 상황에서 유용하게 활용되므로, 각 용법을 이해하고 코드를 더욱 효율적이고 간결하게 작성해보세요!

pdb는 Python의 내장 디버거로, 코드를 실행하면서 특정 지점에서 멈추고 그 시점의 변수 상태를 확인하거나 코드 흐름을 단계별로 추적할 수 있는 강력한 도구입니다. 특히 복잡한 코드나 예기치 못한 오류가 발생하는 부분을 디버깅할 때 pdb를 활용하면 문제의 원인을 빠르게 파악할 수 있습니다.

아래에서는 pdb 사용 방법을 기본부터 설명하고, 실제 코드에서 유용하게 쓸 수 있는 예제를 통해 pdb의 효과적인 사용법을 알아보겠습니다.


1. pdb 기본 사용법: 중단점 설정으로 코드 흐름 추적하기

pdb의 가장 기본적인 기능은 중단점(breakpoint)을 설정해 코드 실행을 멈추고 상태를 점검하는 것입니다. pdb.set_trace()를 사용하면 원하는 지점에서 코드 실행이 멈춰, 변수 값이나 상태를 확인할 수 있습니다.

import pdb

def divide(a, b):
    pdb.set_trace()  # 코드가 이 지점에서 멈추고 디버깅 모드로 전환됩니다.
    return a / b

# 실제 실행
print(divide(10, 2))

pdb 사용 방법

  • 코드가 pdb.set_trace() 부분에서 멈추면, 디버깅 모드로 전환됩니다.
  • 명령어 예시:
    • n (next): 현재 줄을 실행하고 다음 줄로 이동
    • s (step): 함수 내부로 진입하여 실행 흐름을 단계별로 확인
    • c (continue): 다음 중단점까지 실행
    • q (quit): 디버깅 종료

이렇게 pdb를 통해 중단점을 설정하면, 각 변수의 현재 상태를 직접 확인하고 코드의 흐름을 추적할 수 있습니다.


2. pdb로 특정 오류 위치 추적하기

특정 코드에서 예기치 않은 오류가 발생할 경우, try-except 블록을 사용하여 예외 발생 시 pdb를 활성화할 수 있습니다. 이 방식은 오류가 발생한 정확한 위치에서 디버깅을 시작할 수 있어 문제를 신속히 파악하는 데 도움을 줍니다.

import pdb

def divide(a, b):
    return a / b

try:
    result = divide(10, 0)  # ZeroDivisionError 발생
except Exception:
    pdb.post_mortem()  # 예외 발생 시 디버깅 모드로 전환

이 예제는 ZeroDivisionError가 발생하면 자동으로 pdb가 실행되어, 오류가 발생한 시점의 변수 값과 코드 흐름을 추적할 수 있습니다. 이를 통해 디버깅 속도를 높일 수 있습니다.


3. pdb의 주요 명령어와 예제

pdb의 기본 명령어는 디버깅할 때 코드 흐름을 단계별로 조작하는 데 사용됩니다. 자주 사용하는 몇 가지 명령어와 사용 예제를 소개합니다.

  • n (next): 현재 줄을 실행하고 다음 줄로 이동합니다.
  • s (step): 함수 내부로 진입하여 코드 흐름을 확인합니다.
  • c (continue): 다음 중단점까지 코드를 실행합니다.
  • p <변수명>: 특정 변수의 현재 값을 출력합니다. 예: p a
  • l (list): 주변 코드 줄을 표시하여 코드 흐름을 이해하는 데 도움을 줍니다.

예제

import pdb

def calculate_total(price, tax):
    total = price + (price * tax)
    pdb.set_trace()  # 코드가 여기서 멈추고 디버깅 모드로 전환됩니다.
    return total

# 실행
print(calculate_total(100, 0.1))

pdb.set_trace()에서 실행이 멈추면 p price, p tax, p total 등을 입력하여 각 변수의 값을 즉시 확인할 수 있습니다. 이를 통해 계산 과정에서 오류가 발생하는지 쉽게 파악할 수 있습니다.


4. 조건부 중단점 설정하기

코드에서 특정 조건이 충족될 때만 중단점을 설정하고 싶다면, 조건부 중단점을 활용할 수 있습니다. 이렇게 설정하면 모든 반복에서 중단되지 않고, 특정 조건을 충족할 때만 멈추므로 효율적인 디버깅이 가능합니다.

import pdb

def check_number(num):
    if num == 5:
        pdb.set_trace()  # num이 5일 때만 중단점이 활성화됩니다.
    return num * 2

# 실제 실행
for i in range(10):
    print(check_number(i))

이 예제에서는 num5일 때만 pdb가 활성화됩니다. 특정 상황에서만 멈추고 싶을 때 조건부 중단점을 활용하면 코드 흐름을 정확히 파악할 수 있습니다.


5. 함수 호출 흐름을 따라가는 pdb 디버깅

pdb는 함수 호출 구조를 한 줄씩 따라가며 확인할 수 있어, 전체 코드 흐름을 시각적으로 파악하는 데 유용합니다. 함수가 다른 함수 내에서 호출되는 상황에서 특히 유용합니다.

import pdb

def multiply(a, b):
    return a * b

def divide(a, b):
    pdb.set_trace()  # 중단점 설정
    return a / b

def calculate():
    result1 = multiply(5, 4)
    result2 = divide(result1, 2)
    return result2

# 실제 실행
print(calculate())

pdb.set_trace()가 설정된 divide 함수에서 코드가 멈추면, ns 명령어를 통해 각 함수가 호출되는 과정을 한 단계씩 추적할 수 있습니다. 이를 통해 함수 호출 흐름을 보다 정확하게 이해할 수 있습니다.


6. pdb 대신 사용할 수 있는 대안: ipdb와 VSCode 디버거

pdb의 기본 기능에 더해 자동완성과 더 나은 UI를 제공하는 ipdbpdb의 대안으로 자주 사용됩니다. ipdbpdb와 동일한 명령어로 작동하나, 더 편리하게 사용할 수 있습니다.

# ipdb 설치
pip install ipdb

설치 후 pdb.set_trace() 대신 ipdb.set_trace()를 사용하면, 보다 직관적인 디버깅을 경험할 수 있습니다.

또한, VSCode와 같은 IDE의 디버거도 강력한 대안입니다. VSCode 디버거는 코드 라인에서 클릭 한 번으로 중단점을 설정하고, 모든 변수를 직관적으로 확인할 수 있는 UI를 제공합니다. 여러 파일이나 모듈을 한 번에 디버깅해야 하는 복잡한 프로젝트에서 특히 유용합니다.


결론: pdb를 활용한 효율적인 디버깅 습관

이제 pdb의 기본 사용법과 함께 조건부 중단점, 오류 발생 시 자동 디버깅, 함수 호출 흐름 추적 등 다양한 기능을 알게 되었습니다. Python의 내장 디버거인 pdb는 코드의 흐름을 정확히 이해하고 변수 상태를 확인하면서 문제를 빠르게 파악하는 데 큰 도움이 됩니다. 이제 print 디버깅에서 벗어나 pdb로 한층 더 효율적인 디버깅을 시작해보세요!

+ Recent posts