[문법] 가변인자 - *args, **kwargs

2019. 12. 20. 13:20Back-end/Python

  Python에서 함수를 사용하다보면 매개변수를 가변적으로 전달하여 처리할 때가 있다. 가장 대표적인 예가 옵션을 설정할 때이다. Positional Argument floor를 받고, Keyword Argument tv, bed, computer를 받는 예제 함수를 통해 알아보자.

1
2
3
4
5
6
7
8
9
10
11
12
def dochiHouse(floor, tv=None, bed=None, computer=None):
    house = f'아파트 {floor}층' if floor is not None else '단독주택'
 
    things = 0
    if tv is not None:
        things += tv
    if bed is not None:
        things += bed
    if computer is not None:
        things += computer
 
    print(f'우리 집은 {house}이고 {things}개의 가구가 있어')
cs

 

  위 함수를 실행해보자.

1
2
3
4
dochiHouse(9, tv=1, bed=1)
'''
우리 집은 아파트 9층이고 2개의 가구가 있어
'''
cs

  computer 변수를 생략했는데도 정상적으로 출력되는 것을 확인할 수 있다. computer 변수와 같이 초기값을 설정하는 경우 Keyword Argument로 인식하여 생략할 수 있지만, floor 변수와 같이 초기값이 없는 경우 Positional Argument로 인식하여 매개변수의 위치에 맞추어 반드시 입력해주어야 한다.

 

 

그럼 이번에는 새로운 변수( laptop )를 추가하여 다시 실행시켜 보자.

1
2
3
4
5
6
7
dochiHouse(9, tv=1, bed=1, laptop=1)
'''
Traceback (most recent call last):
  File "test.py", line 14, in <module>
    dochiHouse(9, tv=1, bed=1, laptop=1)
TypeError: dochiHouse() got an unexpected keyword argument 'laptop'
'''
cs

  오류가 발생하였다. 왜 그럴까? 매개변수로 지정된 변수 외에는 임의로 추가로 입력할 수 없기 때문이다. 위 예제에서는 laptop 변수는 함수에서 정의되지 않은 매개변수이므로 오류가 발생했다.

 

  지금은 4개의 매개변수를 갖는 함수이지만, 상황에 따라 사용해야 하는 옵션이 수십, 수백가지가 있을 수 있다. 하나의 함수에 이 모든 매개변수를 정의하는 것은 부적절한 방법이다.

 

  이때 사용하는 것이 가변인자(Variadic Parameters)이다.

 

  가변인자는 변수앞에 Asterisk(*) 문자를 사용한다. C언어에서는 변수앞에 *이 있으면 포인터 변수를 가리키지만 Python에서는 가변인자를 나타낸다. 이 문자가 1개인 경우 Positional Argument를 가리키며 주로 *args로 사용하고, 2개인 경우 Keyword Argument를 가리키며 주로 **kwargs를 사용한다.

 

 

  위에서 사용한 함수에 가변인자( *args, **kargs )를 추가해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def dochiHouse(floor, *args, tv=None, bed=None, computer=None, **kwargs):
    house = f'아파트 {floor}층' if floor is not None else '단독주택'
    
    things = 0
    if tv is not None:
        things += tv
    if bed is not None:
        things += bed
    if computer is not None:
        things += computer
 
    for key, value in kwargs.items():
        if key is not None:
            things += value
 
    print(f'우리 집은 {house}이고 {things}개의 가구가 있어')
cs

 

  그리고 이전 함수에서 실패했던 예제를 다시 실행시켜보자.

1
2
3
4
dochiHouse(9, tv=1, bed=1, laptop=1)
'''
우리 집은 아파트 9층이고 3개의 가구가 있어
'''
cs

  새로운 변수가 추가되어도 정상적으로 출력되는 것을 확인할 수 있다.

 

 

  이번엔 가변인자들을 확인해보자.

1
2
3
4
5
6
7
8
9
print( type(args), args )
'''
<class 'tuple'> ()
'''
 
print( type(kwargs), kwargs )
'''
<class 'dict'> {'laptop': 1}
'''
cs

  argsTuple이고 값이 비어있으며, kwargsDictionary이며 새로 추가한 변수가 들어있는 것을 확인할 수 있다.

 

 

 이번엔 값을 더 많이 추가해서 테스트 해보자.

1
2
3
4
dochiHouse(9'가''변''인''자', ac=2, tv=1, fan=5, bed=1, laptop=1)
'''
우리 집은 아파트 9층이고 10개의 가구가 있어
'''
cs

  이번에는 *args 변수 위치에 여러개의 Positional Argument를 추가하였고, Keyword Argument는 순서에 상관없이 입력 해보았는데 잘 돌아간다.

 

 

  이번에도 가변인자들을 출력해보자.

1
2
3
4
5
6
7
8
9
print( type(args), args )
'''
<class 'tuple'> ('', '', '', '')
'''
 
print( type(kwargs), kwargs )
'''
<class 'dict'> {'laptop': 1, 'ac': 2, 'fan': 5}
'''
cs

  args에는 floor 변수를 제외하고 새로 추가한 인자들이 순서대로 저장되어 있고, kwargs에는 새로 추가한 인자들이 정렬되어 있다.

 

 

  이상으로 가변인자에 대해서 알아보았다. 정리하자면 함수의 매개변수는 Positional Argument(PA)Keyword Argument(KA)가 있으며, 작성 순서는 PA, *PA, KW, **KW이다. *PA, KW, **KW, 는 함수 실행시 생략이 가능하지만 PA는 필수로 입력해야 한다. 함수를 생성할때 필수 입력값을 받아야 하는 경우에는 PA를 사용하고, 선택 입력값을 KW로 처리하도록 하자.