06-3 함수와 매개변수 알아보기
윤혜민·박현규 · 30 / 30 절이제 함수의 매개변수를 자세히 알아볼 시간입니다. 함수는 프로그래밍에서 없으면 안 될 정도로 아주 중요한 문법입니다. 그래서 함수의 문법은 개발자들의 편의에 따라 사용 방식을 추가하는 방향으로 발전했습니다. 그래서 매개변수도 아주 다양한 방식으로 사용할 수 있습니다.
매개변수 기초 사용 방법 알아보기
이미 공부한 내용이지만 복습 차원에서 다시 공부해봅시다. 매개변수는 함수를 정의할 때 나중에 함수를 호출하면서 어떤 값을 전달하려고 할 때 사용하는 요소라고 했습니다. 인삿말 예제가 좀 지겹겠지만 다음 코드를 작성하고 실행하면서 매개변수의 기초 사용 방법을 정리해봅시다.
>>> def introduce(name, age, city):
>>> print(f"제 이름은 {name}이고, {age}살이며, {city}에 살고 있습니다.")
>>> introduce("철수", 25, "서울")
>>> introduce("영희", 30, "부산")
[실행 결과]
제 이름은 철수이고, 25살이며, 서울에 살고 있습니다.
제 이름은 영희이고, 30살이며, 부산에 살고 있습니다.
이렇게 함수 선언 시 매개변수의 위치에 맞게 인수를 전달하는 방식을 위치 인수라고 부릅니다. 말 그대로 매개변수의 위치와 인수의 위치를 맞추는 방식입니다.
매개변수의 개수를 고려하지 않으면 어떻게 될까?
이정도면 기초 사용 방법은 충분히 알았으리라 생각합니다. 그런데 매개변수의 개수를 고려하지 않고 함수를 호출하면 어떻게 될까요? 예를 들어서 앞에서 작성한 함수는 3개의 매개변수를 사용하고 있는데 인수를 2개만 전달하면 어떻게 될까요?
>>> introduce("철수", 25)
[실행 결과]
TypeError: introduce() missing 1 required positional argument: 'city'
오류 메시지가 나타났습니다. TypeError는 함수 호출에 문제가 있다는 뜻이고, missing 1 required positional argument: 'city'는 매개변수 city에 해당하는 인수가 빠졌다는 의미입니다. 함수가 3개의 매개변수를 요구하는데 2개만 전달했기 때문에 파이썬이 오류를 발생시킨 겁니다. 이처럼 함수를 정의할 때 매개변수의 개수는 함수 호출 시 인수의 개수에 영향을 주므로 주의해서 사용해야 합니다.
반대로 너무 많은 인수를 전달해도 오류가 발생합니다.
>>> introduce("철수", 25, "서울", "학생")
[실행 결과]
TypeError: introduce() takes 3 positional arguments but 4 were given
이번에는 introduce() takes 3 positional arguments but 4 were given이라는 오류가 나왔습니다. 함수는 3개의 위치 인수를 받는데 4개가 전달되었다는 뜻입니다. 함수를 호출할 때는 정의된 매개변수의 개수와 정확히 일치하는 개수의 인수를 전달해야 한다는 점을 꼭 기억하기 바랍니다.
인수의 순서를 반대로 전달하면 어떻게 될까?
매개변수의 개수가 일치하면 함수 호출에 문제가 없다는 것을 알았습니다. 그렇다면 개수는 맞지만 순서를 바꿔서 전달하면 어떻게 될까요? 파이썬이 알아서 맞춰줄까요, 아니면 그대로 순서대로 전달될까요? 다음 코드를 입력해서 실행해보면 인수의 순서가 얼마나 중요한지 알 수 있을 겁니다.
>>> def introduce(name, age, city):
>>> print(f"제 이름은 {name}이고, {age}살이며, {city}에 살고 있습니다.")
>>> introduce("서울", 25, "철수")
[실행 결과]
제 이름은 서울이고, 25살이며, 철수에 살고 있습니다.
오류는 발생하지 않았지만 결과가 이상합니다. ‘제 이름은 서울이고’라니! 서울이 이름이 되어버렸네요. 파이썬은 전달한 인수 순서대로 매개변수에 할당합니다. 첫 번째 인수 "서울"은 첫 번째 매개변수 name에 들어가고, 두 번째 인수 25는 age에, 세 번째 인수 "철수"는 city에 들어간 겁니다. 좀 더 명확하게 문제를 확인할 수 있는 예제를 하나 더 살펴봅시다.
def calculate_discount(price, discount_rate):
result = price - (price * discount_rate)
return result
wrong_result = calculate_discount(0.2, 10000)
correct_result = calculate_discount(10000, 0.2)
print(f"순서를 바꾼 결과: {wrong_result}원")
print(f"올바른 순서의 결과: {correct_result}원")
[실행 결과]
순서를 바꾼 결과: -1999.8원
올바른 순서의 결과: 8000.0원
할인 계산 함수에서 가격과 할인율의 순서를 바꿔서 전달했더니 -1999.8원이라는 말도 안 되는 결과가 나왔습니다. 0.2원에서 할인을 계산하려다 보니 음수가 나온 겁니다. 올바른 순서로 10000원과 0.2(20% 할인)를 전달해야 8000원이라는 정확한 결과가 나옵니다.
매개변수를 지정해서 호출하는 키워드 인수 알아보기
앞에서 인수의 순서를 바꾸면 예상치 못한 결과가 나온다는 것을 배웠습니다. 하지만 파이썬에는 순서를 신경 쓰지 않고도 정확하게 값을 전달할 수 있는 방법이 있습니다. 바로 매개변수를 명시적으로 지정하여 호출하는 키워드 인수라는 방법입니다. 말 그대로 매개변수를 키워드라고 생각하고 인수를 함께 사용하는 방식입니다. 키워드 인수를 사용하면 매개변수 순서와 상관없이 원하는 매개변수에 정확하게 인수를 전달할 수 있습니다. 다음 코드를 입력해서 실행해보면 매개변수 이름을 명시하면 순서가 바뀌어도 정확하게 작동한다는 것을 알 수 있을 겁니다.
def introduce(name, age, city):
print(f"제 이름은 {name}이고, {age}살이며, {city}에 살고 있습니다.")
introduce(name="철수", age=25, city="서울")
introduce(city="부산", name="영희", age=30)
introduce(age=28, city="대구", name="민수")
[실행 결과]
제 이름은 철수이고, 25살이며, 서울에 살고 있습니다.
제 이름은 영희이고, 30살이며, 부산에 살고 있습니다.
제 이름은 민수이고, 28살이며, 대구에 살고 있습니다.
매개변수 이름을 명시했기 때문에 순서를 바꿔도 모두 올바른 결과가 나왔습니다. 두 번째 호출에서는 city를 가장 먼저 썼지만 정확하게 "부산"이 도시로 들어갔고, 세 번째 호출에서는 age를 먼저 썼지만 역시 제대로 작동했습니다.
키워드 인수를 매개변수 기초 사용 방식과 섞어서 사용할 수도 있습니다. 처음 두 개는 기초 사용 방식으로 전달하고 나머지는 키워드 인수로 전달했습니다. 이렇게 키워드 인수를 섞어 쓸 때는 반드시 위치 인수를 먼저 쓰고 키워드 인수를 나중에 써야 합니다. 순서를 바꾸면 오류가 발생하니 주의하세요.
>>> def make_profile(name, age, city, hobby):
>>> print(f"{name}({age}세)는 {city}에 살며 {hobby}를 좋아합니다.")
>>> make_profile("지호", 27, city="인천", hobby="독서")
[실행 결과]
지호(27세)는 인천에 살며 독서를 좋아합니다.
매개변수 개수를 지정하지 않고 호출하는 방법 알아보기
지금까지는 함수를 정의할 때 매개변수의 개수를 정확히 정하고, 호출할 때도 그 개수에 맞춰서 인수를 전달했습니다. 하지만 때로는 함수를 호출할 때 몇 개의 인수가 전달될지 미리 알 수 없는 상황이 있습니다. 예를 들어 여러 개의 숫자를 더하는 함수를 만들 때, 2개의 숫자를 더할지 10개의 숫자를 더할지 알 수 없다면 어떻게 해야 할까요?
<그림이 있으면 이 글만 가득한 분위기가 좀 완화될 듯>
파이썬에서는 *args라는 특별한 문법을 사용하면 개수에 상관없이 여러 개의 인수를 받을 수 있습니다. 다음 코드를 입력해서 실행해보면 인수를 몇 개 전달하든 상관없이 함수가 작동한다는 것을 알 수 있을 겁니다.
[Note] *args가 아니라 *numbers와 같이 다른 이름을 사용해도 됩니다.
[Note] 매개변수 앞에 별표 *를 붙이면 전달된 모든 인수가 튜플 형태로 묶여서 전달되는 원리입니다.
def add_numbers(*numbers):
total = 0
for num in numbers:
total = total + num
return total
result1 = add_numbers(1, 2, 3)
result2 = add_numbers(10, 20, 30, 40, 50)
result3 = add_numbers(5)
print(f"세 개 더하기: {result1}")
print(f"다섯 개 더하기: {result2}")
print(f"한 개만: {result3}")
[실행 결과]
세 개 더하기 : 6
다섯 개 더하기 : 150
한 개만 : 5
코드를 실행해보면 add_numbers(1, 2, 3)과 같이 3개의 숫자를 인수로 전달하면 1, 2, 3은 함수 내부에서 튜플 (1, 2, 3)으로 처리됩니다. 그래서 for문을 보면 for num in numbers:와 같이 반복문으로 튜플인 numbers에 들어 있는 숫자들을 더할 수 있습니다. 이렇게 *args를 사용하면 함수 호출 시 인수 개수에 제한이 없으므로 함수를 유연하게 사용할 수 있습니다.
[Note] add_numbers(1, 2, 3, 4, 5)도 마찬가지 방법으로 동작합니다.
<1:1 코칭> *args에는 함수 이름을 전달해도 됩니다
파이썬에서는 함수도 하나의 값처럼 다룰 수 있어서, 숫자나 문자열처럼 다른 함수의 매개변수로 넘겨줄 수 있습니다. 이 기능을 활용하면 같은 데이터를 받아서 상황에 따라 다른 동작을 하게 만들 수 있어서 아주 유용합니다. 단 함수를 매개변수로 전달할 때는 괄호 없이 이름만 써야 합니다. 다음 코드를 입력해서 실행해보면 함수를 매개변수로 넘기는 방식이 어떻게 동작하는지 금방 알 수 있을 겁니다.
[Note] add( )처럼 괄호를 붙이면 그 자리에서 함수가 실행되어 결과값이 전달되지만, add처럼 이름만 쓰면 함수 자체가 전달됩니다. 이 차이를 꼭 기억하세요.
def add(a, b): # 더하는 함수 add
return a + b
def subtract(a, b): # 빼는 함수 subtract
return a - b
def calculate(func, x, y):
result = func(x, y)
print(f"{func.__name__} 결과: {result}")
calculate(add, 10, 3)
calculate(subtract, 10, 3)
