함수는 일정한 작업을 수행하는 코드? 프로그램이라고도 할 수 있습니다.
일반적으로 수학시간에 배웠던 함수와 개념적으로는 동일하다고 할 수 있습니다. input
을 입력하면 어떤 과정을 통해 output
이 도출되는 간단한 로직입니다.
함수를 사용하는 이유
함수의 로직은 간단하다. input으로 어떤 입력값을 넣고 계산을 통해 output이 출력되는 구조이다.
파이썬에서는 input 을 parameter라 하고 output을 return 값이라고 한다.
def 함수명(parameter):
문장1
문장2
...
문장n
return 값
parameter
와 return
값은 옵션이다. parameter
와 return
값이 없는 함수도 존재한다.
함수는 생성만 한다고 값이 도출되지 않습니다. 함수의 호출로 값을 생성할 수 있습니다.
함수명()
위와 같이 코드를 작성해야 함수를 호출하는 것입니다.
함수의 파라미터가 전달되는 로직을 한번 살펴보자.
def text(a, b):
print(f"{a} 수도는 {b}")
text("한국", "서울")
함수의 생성부터 호출까지 기본 구조이다. 결과값은 한국 수도는 서울
이 출력된다.
f-string
은 기본 문법 글에서 학습한 적이 있다.
함수의 호출에서 파라미터 값을 넣었더니 return값이 출력되었다.
기본적인 함수 구조에서 파라미터 순서를 순서대로 주지 않아도 되는 방법이 있습니다.
def text(a, b):
print(f"{a} 수도는 {b}")
text(b="서울", a="한국")
다음과 같이 작성해도 결과값은 동일합니다.
함수에 주어진 파라미터 순서대로가 아닌 파라미터에 값을 주어서 출력할 수 있습니다.
이 방식을 Keyword Arguments
방식이라고 합니다.
이 방식의 장점은 가독성이 높아지고 실수로 값을 섞어 입력해도 금방 찾을 수 있다는 것입니다.
기본 형식의 함수 호출로 작성했을 때 파라미터를 실수로 바꿔 입력했을 때 방대한 양의 자료에서는 바뀌었는지 실수했는지 찾기가 힘들 수 있습니다. 그렇기 때문에 파라미터에 값을 지정해놓으면 상대적으로 값이 바뀔 확률이 줄어듭니다.
위에서 봤던 두 방법을 혼합하여 사용할 수 있습니다.
예시를 통해 살펴보겠습니다.
def text(a, b):
print(f"{a} 수도는 {b}")
text("한국", b="서울")
여기서 중요한것은 keyword arguments
는 순서가 바뀌어도 상관 없지만 positional arguments
부분은 순서를 지켜줘야 한다는 것입니다.
def text(a, b):
print(f"{a} 수도는 {b}")
text(b="서울", "한국")
SyntaxError: positional argument follows keyword argument
에러가 나는 이유는 keyword argument
가 positional argument
보다 더 앞으로 위치되어 함수가 호출되었기 때문입니다.
Positional arguments
는 순서를 지켜주어야 하는데 순서가 틀렸기 때문에 에러가 나는것입니다.
함수를 정의할 때 파라미터에 기본값을 미리 정해놓을 수 있습니다.
def text(a="한국", b="서울"):
print(f"{a} 수도는 {b}")
text() # 한국 수도는 서울
def text(a, b="서울"):
print(f"{a} 수도는 {b}")
text("한국") # 한국 수도는 서울
둘 다 같은 값을 출력합니다. 기본값이 정해진 파라미터는 함수가 호출될 때 값이 넘겨지지 않아도 출력됩니다.
여기서 주의할 점은 default 값
이 정의된 parameter
가 default 값
이 정의 되지 않은 parameter
보다 먼저 위치해 있으면 안된다는 점입니다.
파라미터의 기본값 설정은 뒤에서 부터 해야합니다.
def text(a="한국", b):
print(f"{a} 수도는 {b}")
text("서울") # SyntaxError: non-default argument follows default argument
fault value parameter
를 non-default value parameter
앞에 정의하면 오류나는 이유는 파이썬 인터프리터가 코드를 읽을 때 어느 파라미터(a, b)가 생략된지 모른다는 것이다.
즉 positional arguments
와 keyword arguments
의 특성 때문에 그렇다 positional arguments
은 생략이 불가능하고 정해진 위치에 따라 인자를 전달해야한다. 그러나 keyword arguments
의 경우 함수 선언시 디폴트값을 설정할 수 있으며, 만약 인자를 생략할 시 해당 디폴트값이 인자의 값으로 들어간다. 즉, 이 형태의 인자는 생략이 가능하다. 따라서, 여기서 알 수 있는건 keyword arguments
의 경우 생략이 가능하기 때문에, positional arguments
이전에 선언될 수는 없다.
파이썬에서는 이런 문법을 허용하지 않고 있으면 뒤에 있는 파라미터에도 기본값을 설정해주어여지 오류가 생성되지 않는다.
위치인수는 위에서 살펴봤고 가변인수에 대해 알아보자.
*args (variable length arguments): 가변인수
란 인수의 개수가 변할 수 있다는 의미이며 임의의 개수의 인자를 튜플 형태로 저장한다. ('....','....')
*args
의 이름은 *...
다른 이름을 사용하여도 무방하다.
def func_param_with_var_args(name, *args, age):
print("name=",end=""), print(name)
print("args=",end=""), print(args)
print("age=",end=""), print(age)
func_param_with_var_args("정우성", "01012341234", "seoul", 20)
#TypeError: func_param_with_var_args() missing 1 required keyword-only argument: 'age'
위에서 봤던 디폴트값을 줬을 때 나는 오류랑 비슷한 맥락이다.
임의의 개수의 인자를 받기 떄문에 뒤에 오는 파라미터가 값을 전달받지 못한다. 해결방법은 두가지로 볼 수 있다.
가변인자 *args
와 age
의 위치를 바꿔주면 된다. 하지만 그렇게 되면 print
호출문의 순서도 바꿔줘야 하는 단점이 있다.
두번째 방법으로는 age
를 position argument
에서 keyword argument
로 바꿔주면 된다.
def func_param_with_var_args(name, *args, age):
print("name=",end=""), print(name)
print("args=",end=""), print(args)
print("age=",end=""), print(age)
func_param_with_var_args("정우성", "01012341234", "seoul", age=20)
# name=정우성
# args=('01012341234', 'seoul')
# age=20
가변 키워드 인수(variable length keyword arguments)
:
임의의 개수의 키워드를 받는 인자이다. *kwargs
로 사용하고 전달받은 키워드 인자를 딕셔너리 형태로 저장한다. {'a': '강아지', 'b': '고양이'}
def func_param_with_kwargs(name, age, **kwargs, address=0):
print("name=",end=""), print(name)
print("age=",end=""), print(age)
print("kwargs=",end=""), print(kwargs)
print("address=",end=""), print(address)
func_param_with_kwargs("정우성", "20", mobile="01012341234", address="seoul")
# SyntaxError: invalid syntax
고민해봤지만 왜 안될까? 라는 생각이 든다. 위치인자는 앞에 위치시켜 값을 잘 받게 해줬고 가변인자 뒤에 위치인자가 존재하는 것도 아니고 디폴트값을 줬기때문에 출력될 것만 같다. 하지만 안된다.
해볼 수 있는 시도는 **kwargs
와 address
의 자리를 바꿔 보는 시도를 해봤다 조금 허무하지만 잘 실행이된다.
def func_param_with_kwargs(name, age, address=0, **kwargs):
print("name=",end=""), print(name)
print("age=",end=""), print(age)
print("kwargs=",end=""), print(kwargs)
print("address=",end=""), print(address)
func_param_with_kwargs("정우성", "20", mobile="01012341234", address="seoul")
# name=정우성
# age=20
# kwargs={'mobile': '01012341234'}
# address=seoul
근데 여기서 의문점은 address에 이미 디폴트 값이 존재하는데 address=0은 뭐지? 라는 생각이 든다. 그래서 0을 지워봤다 당연히 똑같은 결과값이 도출될 것이다. 앞의 두 인자와 같은 위치인자로 바뀐것이다.
def func(non-default parameter, default value parameter, 가변 키워드 인자)
다음과 같은 순서로 파라미터를 배치해야한다.
마지막 문제를 한번 살펴보자.
def mixed_params(name="아이유", *args, age, **kwargs, address):
print("name=",end=""), print(name)
print("args=",end=""), print(args)
print("age=",end=""), print(age)
print("kwargs=",end=""), print(kwargs)
print("address=",end=""), print(address)
mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")
이번에도 제자리를 한번 찾아보자. 일단 age,address,name 이 위치 인자로 보인다. 하지만 name은 디폴트값이 있으니 뒤로 뺴겠다. 1차시도
(age, address, name="아이유", *args, **kwargs) 의 순서로 출력했으나 실패.
일단은 두번째 값에 이름을 받아야하니 위치를 조금 조정하자.
(age, name="아이유", address, args, **kwargs)로 변경했다. 하지만 실패.
address값을 살펴보니 마지막에 있다. 그럼 일단 자리를 맞춰주기 위해 끝으로 보내야겠지만 가변키워드인자가 있기 때문에 그 앞에 위치시킨다.
(age, name="아이유", args, address, **kwargs) 로 바꿧더니 잘 출력되었다.
참고 사이트를 찾아보니 Keyword-Only-Argument 라는 특수인수가 있는데 가변 위치 인수 뒤에 위치하며 non-default Keyword-Only-Argument 와 default Keyword-Only-Argument 로 나누고 가변 키워드 인수 앞에 위치한다.