위코드에서 파이썬 매개변수에 대한 3가지 질문을 받고 생각한 점들을 기록합니다.
함수를 정의 할때 default value parameter를 non-default value parameter 앞에 정의 하면 안 되는 이유는?
def func(first = 1, second):
print(first)
print(second)
func(2)
위 코드에선 다음과 같은 에러가 난다.
# SyntaxError: non-default argument follows default argument
그러나 파이썬에서는 문법적인 오류라고 할 뿐, 자세한 이유는 설명해주지 않는다. non-default argument가 default argument 뒤에 오지 않게만 해주라고만 한다.
보통 같으면 대충 그렇구나 하고 넘어갈 에러지만 질문을 받은 김에 깊이 생각을 해보려고 한다.
그 이유가 뭘까?
처음에 떠올랐던 생각은, 그냥 "나름의 원칙이 필요하기 때문이 아닐까?" 였다.
그러나 생각을 한 번 더 해보니까, 생각보다 깊은 뜻이 있었다!
default value parameter을 쓰는 의의를 생각해보자.
default value parameter을 쓰는 이유는 뭘까?
가장 큰 이유는 '자주 쓰일 값에 대해 반복을 줄이기 위해서'라고 생각한다.
def greeting(param):
print(param)
greeting("안녕하세요")
greeting("안녕하세요")
greeting("안녕하세요")
greeting("잘 부탁드려요")
greeting("좋은 아침이예요")
우리가 매일 하는 인사를 함수라고 생각하면, 대부분의 argument는 "안녕하세요"이다. 다른 인삿말이 굳이 필요한가 싶을 정도로 자주 쓰는 말이다.
그런데 그렇다고 해서 인자값을 받지 않고 평생 모든 인삿말을 "안녕하세요"라고 한다면, 상황에 따라 대화에 변화를 줄 수 없을 것이다.
그래서 쓰는 게 default value parameter이다. 별 생각이 없다면 "안녕하세요"를 default value로 하되, 평소와 달리 변화를 주고 싶다면 argument을 넣어주면 된다.
def greeting(param = "안녕하세요"):
print(param)
greeting() # 안녕하세요
greeting() # 안녕하세요
greeting("잘 부탁드려요") # 잘 부탁드려요
greeting("좋은 아침이예요") # 좋은 아침이예요
default value parameter을 일반 parameter 앞에 놓는 순간, default value parameter을 쓰는 의의가 없어진다고 볼 수 있다.
처음 봤던 코드로 돌아가보자.
def func(first = 1, second):
print(first)
print(second)
func(1, 3)
func(1, 20)
이 코드는 설령 에러를 내뱉지 않더라도, 좋지 않은 코드이다.
애초에 반복을 줄이려고 default value parameter을 쓰는데, default value parameter을 앞순서에 놓게 되면 매번 인자값을 넣어줘야 하기 때문이다.
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
는 정해진 인수 외의 모든 argument를 하나의 튜플로 만드는 역할을 하는 키워드이다.
그래서 여러 parameter의 사이에 *args
를 놓게 되면 *args
는 그 뒤에 오는 모든 argument들을 포함하려고 한다.
그 결과로 *args
뒤에 오는 parameter은 몇 개가 되든 의미가 없어진다.
def func(*args, 뒤는, 의미없음, ...):
해결법은 간단하다. *args
의 뒤에 다른 parameter가 오지 않게 해주면 된다.
def func_param_with_var_args(name, age, *args):
print("name=",end=""), print(name)
print("args=",end=""), print(args)
print("age=",end=""), print(age)
func_param_with_var_args("정우성", 20, "01012341234", "seoul")
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")
위 코드에는 일단 문법의 문제가 있다.
위에서 말한 인수의 위치문제가 있으므로(지정 parameter과 일반 paratmeter의 순서, *args
와 다른 parameter간의 순서), 다음과 같이 바꾼다.
def mixed_params(age, address, name="아이유", *args, **kwargs):
print(name)
print(age)
print(args)
print(kwargs)
mixed_params(20, "01012341234", "정우성", "male" , mobile="01012341234", address="seoul")
그래도 위의 코드는 에러가 생긴다.
TypeError: mixed_params() got multiple values for argument 'address'
한 인자값 'address'에 여러개의 값을 전달받았다고 한다.
맞는 말이다!
keyword parameter에 쓰이는 이름도 결국 parameter간에 구분이 되어야 한다.
따라서 위의 코드에서는 둘 중 하나를 포기하거나, 이름을 바꿔야 한다.
나라면 이름을 바꾸겠다.
def mixed_params(age, address, name="아이유", *args, **kwargs):
print(name)
print(age)
print(args)
print(kwargs)
mixed_params(20, "01012341234", "정우성", "male" , mobile="01012341234", location ="seoul")
배운대로만 코드를 쓰다보면, 그것이 왜 생겨났고 왜 필요한지를 잊게 된다. 그리고 더 좋은 방법을 찾을 기회가 없어지는 것 같다.
앞으로 파이썬을 공부하면서 다른 문법과 표현에 대해서도 한 번씩 생각해봐야겠다.