개발기록장

[Python] 가변 인수와 가변 키워드 인수 + 파라미터 순서 본문

TIL/Python

[Python] 가변 인수와 가변 키워드 인수 + 파라미터 순서

yangahh 2021. 1. 14. 21:27

 

1. Variable length Arguments (가변 인수)

 

파이썬에서는 함수에서 입력값이 몇 개가 될지 모를 때을 위해 가변 인수를 제공한다.

아래 예제를 통해 알아보자.

def add_many(*args):  # 가변 인수는 파라미터 앞에 *을 붙인다.
    print(args)
    result = 0
    for i in args:
        result += i

    return result


print(add_many(1, 2, 3, 4, 5))

# 결과
>> (1, 2, 3, 4, 5)
15

  • 위 add_many 함수처럼 입력값이 몇 개이든 상관없다.
  • *args처럼 파라미터 이름 앞에 *을 붙이면 그 파라미터는 가변 인수로 설정되고, 출력 결과에서 볼 수 있듯이 입력받은 모든 값을 하나의 튜플로 모아서 저장한다.

       ** 참고) args는 arugments의 약자이며 가변 인수를 설정할 때 관례적으로 자주 사용한다. 다른 이름으로 사용해도 된다.

 

 

 

 

 

2. Variable length keyword Arguments (가변 키워드 인수)

 

가변 인수와 더불어 함수에서 입력값이 몇 개가 될지 모를 때 사용할 수 있는 또 다른 방법으로 가변 키워드 인수를 사용하는 방법이 있다.

이것도 아래 예제를 통해 알아보자.

def total_score(**kwargs):  # 가변 키워드 인수는 파라미터 이름 앞에 **를 붙여서 설정한다.
    print(kwargs)

    total_score = 0
    for key, value in kwargs.items():
        print(f'{key} : {value}')
        total_score += value

    return total_score


print(total_score(kor=100, math=80, eng=90))

# 결과
>> {'kor': 100, 'math': 80, 'eng': 90}
kor : 100
math : 80
eng : 90
270

  • total_score 함수처럼 호출 시 입력 값이 몇 개이든 상관없다.
  • **kwargs처럼 파라미터 이름 앞에 **를 붙이면 가변 키워드 인수로 설정된다.
  • 호출할 때를 보면 키워드를 지정해서 값을 전달함을 알 수있는데, 가변 인수와 비교하자면가변 인수는 positional arguments를 기반으로 하고, 가변 키워드 인수는 keyword arugments를 기반으로 한다고 할 수 있다.
  • 위 total_score에서 kwargs를 출력한 결과에서 볼 수 있듯, 입력값을 모두 딕셔너리로 모아서 저장한다.

       ** 참고) kwargs는 keyword arugments의 약자이며 args와 마찬가지로 가변 키워드 인수를 설정할 때 관례적으로 사용한다. 이것 역시 다른 이름으로 사용해도 된다.

 

 

 

 

 

3. 파라미터 지정 순서

함수 정의 시 가변 인수, 가변 키워드 인수, default value 파라미터를 사용할 때 파라미터 지정 순서를

아래 3가지의 에러 케이스를 통해 확인해보자.

 

Case 1. 위치 인수(positional 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", 20)


# 결과
>> Traceback (most recent call last):
  File "test.py", line 8, in <module>
    func_param_with_var_args("정우성", "01012341234", "seoul", 20)
TypeError: func_param_with_var_args() missing 1 required keyword-only argument: 'age'

 

위에 나온 에러를 보면 함수 호출 시 에러가 난 것을 확인할 수 있는데, 파이썬 인터프리터가 age에 전달되는 함수가 무엇인지 모르는 것 같다.

가변 인수인 *args가 위치 인수(age)보다 앞에 쓰여서 어디까지가 *args인지를 알 수 없기 때문이다.

 

 

  • 해결 방안 1) *args를 모든 위치 인수 뒤에 정의되게 수정
def func_param_with_var_args(name, age, *args):  # *args를 위치 인수보다 뒤에 가도록 변경
    print("name=", end=""), print(name)
    print("args=", end=""), print(args)
    print("age=", end=""), print(age)


func_param_with_var_args("정우성", 20, "01012341234", "seoul")  # 변경된 파라미터 순서에 맞게 입력값 순서도 변경 


# 결과
name=정우성
args=('01012341234', 'seoul')
age=20

 

  • 해결 방안 2) age에 값을 전달할 때 키워드 인수로 전달
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)  # 키워드 인수를 통해 age에 전달될 값을 명확히 해준다.


# 결과
name=정우성
args=('01012341234', 'seoul')
age=20

>> 두 경우 모두 에러가 나지 않고 함수 호출이 잘 되었다.

 

  • 결론

- 함수 정의 시 가변 인수(*args)는 모든 위치 인수(name, age)의 뒤에 위치해야 한다.
- 또는 다른 위치 인수들을 키워드 인수로 값을 지정하여 넘겨주는 방법도 있다.

 

 

Case 2. 위치 인수, 가변 키워드 인수 그리고 default value 파라미터
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")


# 결과
>> File "test.py", line 1
    def func_param_with_kwargs(name, age, **kwargs, address=0):
                                                    ^
SyntaxError: invalid syntax

함수 선언 시 Syntax Error가 난다. 왜 그럴까?

 

가변 키워드 인수도 가변 인수와 마찬가지로 정해지지 않은 개수의 인자값을 받을 때 사용된다.

따라서 가변 키워드 인수 역시 모든 위치 인수 뒤에 정의되어야함을 유추할 수 있다.

그리고 default value가 적용된 address 파라미터는 non-default 파라미터 뒤에 위치해야하므로 다음과 같이 수정해보자.

 

 

  • 수정 코드
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

 

  • 결론

- 함수 정의 시 가변 키워드 인수(**kwargs)도 가변 인수(*args)와 마찬가지로 모든 위치 인수 뒤에 위치해야 한다.

 

 

 

 

Case 3. 위치 인수, 키워드 인수, 가변 인수, 가변 키워드 인수 그리고 default value 파라미터
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")


# 결과
>> File "test.py", line 2
    def mixed_params(name="아이유", *args, age, **kwargs, address):
                                                             ^
SyntaxError: invalid syntax

이것 역시 함수 정의 시 Syntax Error가 난다.

 

문제를 해결하기 전에 우선, 이 함수 호출이 의도하는 결과와 문제점을 정리해보자.

 

- name = "정우성" 

- *args = ("01012341234", "male")

- age = 20 

- **kwargs = {mobile = "01012341234"}

- address = "seoul"  

 

우선 default value가 설정되어있는 name 파라미터를 non-default 파라미터인 age와 address보다 뒤로 옮긴다.

case1과 case2에서 알 수 있었던 것을 토대로 가변 인수와 가변 키워드 인수를 위치 인수들 뒤로 위치를 변경해보자.

그리고 case1과 case2를 토대로 가변 인수를 가변 인수가 아닌 것 인수들 뒤로 이동시킨다.

바뀐 파라미터의 위치에 맞게 함수를 호출하는 곳에서도 인수들의 위치를 조정해줘야 한다.

 

  • 수정 코드
def mixed_params(age, address, name="아이유", *args, **kwargs):
    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, address="seoul", "정우성", "01012341234", "male", mobile="01012341234")


# 결과
>> File "test.py", line 11
    mobile="01012341234")
                        ^
SyntaxError: positional argument follows keyword argument
             
             

그럼에도 불구하고 에러가 났다.

구글링 해보니 Keyword-Only arguments라고 부르는 특수 인자값으로 이는 *args보다는 뒤에 위치해야 한다고 한다.

 

아래와 같이 다시 수정해보니 해결되었다.

 

  • 수정 코드 2
def mixed_params(age, name="아이유", *args, address, **kwargs):
    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",
             address="seoul", mobile="01012341234")


# 결과
name=정우성
args=('01012341234', 'male')
age=20
kwargs={'mobile': '01012341234'}
address=seoul

 

  • 결론

함수 정의 시 파라미터 순서 정리

참고 링크 >> getkt.com/blog/python-keyword-only-arguments/getkt.com/blog/python-keyword-only-arguments/

 

  1. 일반 positional 인수
  2. default value가 설정된 인수
  3. 가변 인수 (*args)
  4. non-default인 Keyword-Only 인수 (키워드 인수로 값을 전달할 때)
  5. default가 설정된 Keyword-Only 인수
  6. 가변 키워드 인수 (**kwargs)

       ** 단, 4번 5번은 번갈아가면서 위치함.