본문 바로가기
Python/Python 개념

*args와 **kwargs

by hyun-am 2020. 9. 14.

*args와 **kwargs를 이용하면 좋은점

 

먼저 이 두가지를 이용하면 함수가 선택적 인자를 받아들일 수 있으므로 모듈 및 클래스에서 유연한 API를 만들 수 있습니다.

먼저 간단한 함수 하나를 만들겠습니다.

def foo(required, *args, **kwargs):
    print(required)
    if args:
        print(f'args 호출 : {args}')
    if kwargs:
        print(f'kwargs 호출 : {kwargs}')

함수 앞에는 최소한의 'required'라는 인자 하나를 필요로 하지만 추가 위치 인자와 키워드 매개 변수도 추가로 사용할 수 있습니다.

이제 추가 인자를 사용하여 함수를 호출하면 매개 변수 이름 앞에

* 접두사가 있어서 args가 여분의 위치 인자를 튜플로 수집합니다.

마찬가지로 kwargs는 매개변수 이름 앞에 ** 접두사가 있기 때문에 딕셔너리로 추가 키워드 인자를 수집합니다.

만약 함수에 추가 인자가 없으면 args와 kwargs는 비어 있을 수 있습니다.

먼저 아무런 인자 없이 foo 함수를 호출하겠습니다.

print(foo())
# 출력 값
# TypeError: foo() missing 1 required positional argument: 'required'

그러면 required라는 인자가 필요하다는 오류가 나오는 것을 확인할 수 있습니다.

 

다음은 string 값을 하나 입력하고 호출해보겠습니다.

foo('hi python')
# 출력 값
# hi python

이제 남은 매개 변수들을 잘 입력하고 호출해보겠습니다.

foo('hello',1,2,3,key1='value',key2=999)
# 출력 값
# hello
# args 호출 : (1, 2, 3)
# kwargs 호출 : {'key1': 'value', 'key2': 999}

 

선택적 또는 키워드 매개 변수 전달하기

 

한 함수에서 다른 함수로 선택적 또는 키워드 매개 변수를 전달할 수 있습니다. 인자를 전달할 함수를 호출할 때 인자 풀기 연산자 *와 **를 사용하면 됩니다. 또한 인자를 전달하기 전에 수정할 수 있는 기회를 줍니다. 예시 코드는 아래와 같습니다.

def foo(x, *args, **kwargs):
    kwargs['name'] = 'Alice'
    new_args = args + ('extra',)
    bar(x,*new_args,**kwargs)

 

이것을 이용하면 함수를 작성하고 서브클래싱 하는데 유용합니다. 예를 들어 부모 클래스 생성자의 시그니처 전체를 자식 클래스에 복제하지 않아도 부모 클래스의 동작을 확인할 수 있습니다. 또한 언제 변경될지 모르는 API로 작업할 때 매우 편리합니다.

 

class Car:
    def __init__(self,color,mileage):
        self.color = color
        self.mileage = mileage

class AlwaysBlueCar(Car):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.color = 'blue'


print(AlwaysBlueCar('green',48392).color)
# 출력 값 
# blue

 

또한 이것을 데코레이터 함수와 사용하면 원래 함수의 시그니처를 복사하지 않아도 유지관리를 쉽게 할 수 있습니다.

import functools
def trace(f):
    @functools.wraps(f)
    def decorated_function(*args,**kwargs):
        print(f,args,kwargs)
        result = f(*args,**kwargs)
        print(result)
    return decorated_function

@trace
def greet(gretting, name):
    return f'{gretting},{name}!'

print(greet('Hello','bob'))

# 출력 값
# <function greet at 0x7f7fdfa11700> ('Hello', 'bob') {}
# Hello,bob!
# None

 

⭐️ 여기서 참고사항은 꼭 *args, **kwargs라고 호칭을 안 해도 됩니다. *parms, ** argv등 다양하게 호칭할 수 있습니다. 왜냐하면 실질적인 문법은 별 하나와 별 두개(*, **) 이기 때문입니다.

 

*과 **을 이용한 함수 인자 풀기

 

*과 **을 이용하면 연속된 데이터나 딕셔너리에서 함수 인자를 풀어낼 수 있습니다. 예를 들겠습니다.

vect_lst = [1,2,3,4,5]
vect_tuple = (1,2,3,4,5)
vect_set = {1,2,3,4,5}

print(*vect_lst)
print(*vect_tuple)
print(*vect_set)

# 출력 값
# 1 2 3 4 5
# 1 2 3 4 5
# 1 2 3 4 5

출력 값을 보면 리스트에 있는 값들이 풀어 내어서 출력된 것을 확인할 수 있습니다.

 

다음은 dict 값을 보여주겠습니다.

def print_vector(x,y,z):
    print('<%s, %s, %s>'%(x,y,z))

vect_dict = {
    'x':1,
    'y':2,
    'z':3
}
print_vector(*vect_dict)
print_vector(**vect_dict)

## 출력 값
# <x, y, z>
# <1, 2, 3>

이런식으로 *하나가 있을 경우 key값을 출력하고 **가 두개 있을 경우 value값을 출력해주는 것을 확인할 수 있습니다.

'Python > Python 개념' 카테고리의 다른 글

파이썬 자료구조(심화)-1  (0) 2020.09.16
얕은 복사와 깊은 복사  (0) 2020.09.16
파이썬 - 데코레이터  (0) 2020.09.14
파이썬 문자열 다루기  (1) 2020.05.25
파이썬 - list comprehension  (0) 2020.05.24

댓글