2.15. 인수

함수는 여러 가지 방식으로 호출할 수 있으며, 그 매개변수도 여러 형태로 선언할 수 있습니다. 그 조합들은 처음에는 위압적으로 보이지만, 실제로는 서너 가지 패턴이 거의 모든 것을 다룹니다.

2.15.1. 위치 인수와 키워드 인수

가장 단순한 호출은 인수를 위치로 전달합니다. 첫 번째 값은 첫 번째 매개변수로, 두 번째는 두 번째로, 이런 식으로 이어집니다:

def rect(x, y, w, h):
    return (x, y, w, h)

rect(10, 20, 100, 50)

같은 호출을 인수를 키워드로 전달하여 각 매개변수를 명시적으로 이름 붙일 수도 있습니다:

rect(x=10, y=20, w=100, h=50)

키워드 인수는 순서에 무관하며, 타이핑이 더 많아지는 대신 호출을 자체 문서화되게 만듭니다. 위치 인수와 키워드 인수는 한 호출에서 섞을 수 있지만, 모든 위치 인수는 어떤 키워드 인수보다 앞에 나와야 합니다:

rect(10, 20, w=100, h=50)         # OK
rect(x=10, 20, 100, 50)           # SyntaxError

2.15.2. 기본값

매개변수는 호출자가 값을 제공하지 않을 때 사용할 기본값을 선언할 수 있습니다:

def greet(name, greeting="hello"):
    print(greeting, name)

greet("Alice")                    # hello Alice
greet("Alice", "hi")              # hi Alice
greet("Alice", greeting="hey")    # hey Alice

기본값이 있는 매개변수는 def 줄에서 기본값이 없는 매개변수 뒤에 와야 합니다.

경고

기본값은 매 호출마다가 아니라 def가 실행될 때 한 번만 평가됩니다. 가변 기본값([], {})을 사용하면 기본값을 취하는 모든 호출에서 같은 객체가 공유됩니다. 대신 None을 센티넬로 사용하세요:

def append_to(item, target=None):
    if target is None:
        target = []
    target.append(item)
    return target

2.15.3. 가변 길이: *args**kwargs

*가 앞에 붙은 매개변수는 남은 위치 인수를 모두 tuple로 모읍니다. **가 앞에 붙은 매개변수는 남은 키워드 인수를 모두 dict로 모읍니다. 관례적인 이름은 argskwargs이지만, 어떤 식별자든 사용할 수 있습니다:

def report(label, *values, **options):
    print(label, values, options)

report("temps", 21, 22, 23, unit="C", precision=1)

출력:

temps (21, 22, 23) {'unit': 'C', 'precision': 1}

함수가 둘 다 필요로 하는 경우는 드뭅니다. 가장 흔한 용도는 래퍼에서 내부 호출로 인수를 전달하는 것입니다:

def log_and_call(func, *args, **kwargs):
    print("calling", func.__name__)
    return func(*args, **kwargs)

호출 지점에서의 대칭적인 구문은 이터러블을 위치 인수로(*) 또는 dict를 키워드 인수로(**) 언패킹합니다:

point = (10, 20, 100, 50)
rect(*point)                      # same as rect(10, 20, 100, 50)

kwargs = {"x": 10, "y": 20, "w": 100, "h": 50}
rect(**kwargs)                    # same as rect(x=10, y=20, ...)

2.15.4. 키워드 전용 매개변수

매개변수 목록에서 (이름에 붙지 않은) 단독 *는 그 뒤에 오는 모든 매개변수를 키워드 전용으로 표시합니다. 즉 호출자는 반드시 이름을 사용해야 합니다:

def crop(buffer, *, x, y, w, h):
    ...

crop(buffer, x=0, y=0, w=100, h=100)   # OK
crop(buffer, 0, 0, 100, 100)           # TypeError

불리언 플래그나, 호출 지점에서 값만 덩그러니 있으면 의미가 자명하지 않은 다른 인수에 이를 사용하세요.