파이썬으로 작성된 코드를 보다보면 함수 인자에 *args, **kwargs라는 생소한 인자가 들어간다. 이 키워드들이 어떤 것인지, *가 무엇을 의미하는지 확인해본다.
packing/unpacking
packing은 여러 인자를 하나의 값으로 묶어주는 기능이다. 함수 인자의 이름 앞에 *를 붙여주면 된다.
x
def foo1(*args): print("type", type(args)) print("value", args)foo1(1, 2, 3, 4)위 코드를 실행하면 아래와 같이 출력된다.
xxxxxxxxxxtype <class 'tuple'>value (1, 2, 3, 4)foo1함수의 인자에 1, 2, 3, 4를 전달했으며 함수는 이 값들을 튜플의 형태로 가져온다. 따라서 인자의 갯수에 상관없이 함수를 호출할 수 있다.
unpacking은 packing과 반대로 하나의 값을 여러 인자로 나눈다. 여기서 하나의 값은 리스트, 튜플, 셋, 딕셔너리와 같이 여러 값들을 묶은 자료형을 나타낸다. 이 자료형들이 가진 값들의 원소 하나씩 풀어내는 것이다.
x
def foo2(a, b, c, d): print(a, b, c, d)l = [1, 2, 3, 4]foo2(*l) # unpackingfoo2는 4개의 인자를 가진 함수이다. 4개가 원소인 리스트 l을 unpacking하여 foo2를 호출한 것이다.
가변 인자
가변인자를 사용하는 함수를 작성해본다.
x
def log(message, *values): if not values: print(message) return value_str = ", ".join(str(x) for x in values) print(f"{message}: {value_str}")log("numbers", 1, 2, 3, 4)log("hello world")l = [5, 6, 7, 9]log("list numbers", *l)위의 log함수는 가변인자 values를 사용한다.
가변인자를 사용할 때 제너레이터를 전달할 경우 주의해야한다. 함수 호출시 튜플로 변환해야하기 때문에 인자의 제너레이터를 반복하게 되고 이는 많은 메모리를 소모할 수 있다.
키워드 인자
파이썬에서는 함수 호출시 키워드를 사용해 인자를 전달할 수 있다.
xxxxxxxxxxdef foo3(first, second): print(f"f: {first}, s: {second}")foo3(1, 2)foo3(1, second=2)foo3(first=1, second=2)foo3(second=2, first=1)함수를 호출할 때 인자의 이름=값 형식으로 인자의 값을 대입할 수 있다.
딕셔너리 자료형을 사용해서도 키워드 전달 방식으로 함수를 호출할 수 있다.
x
dic = { "first": 1, "second": 2,}foo3(**dic)"""기존 인자와 함께 사용할 수 있다."""dic = { "second": 2,}foo3(1, **dic)dic = { "first": 1,}foo3(second=2, **dic)"""여러 딕셔너리를 사용해 호출 가능하다."""dic1 = { "first": 1,}dic2 = { "second": 2,}foo3(**dic1, **dic2)foo3(**dic2, **dic1)**연산자는 딕셔너리의 값을 함수 인자에 대응하는 키에 대응하여 호출하게 한다.
함수의 인자에 **연산자를 넣으면 아래와 같다.
xxxxxxxxxxdef kwpacking(**kwargs): print(kwargs) print(type(kwargs)kwpacking(a=1, b=2, c=3)xxxxxxxxxx{'a': 1, 'b': 2, 'c': 3}<class 'dict'>인자로 딕셔너리를 전달할 때와는 반대로 인자의 **는 호출되는 함수의 키워드 인자를 딕셔너리 형태로 변환해준다.
위에서 살펴본 *args와 **kwargs를 동시에 사용할 수 있다.
x
def foo4(p, *args, **kwargs): print("param", p) print("args", type(args), args) print("kwargs", type(kwargs), kwargs)foo4(1, 2, 3, a=1, b=2)l = [2, 3]foo4(1, *l, a=1, b=2)dic = { "a": 1, "b": 2}foo4(1, 2, 3, **dic)xxxxxxxxxx// 세 번 호출한 foo4는 모두 동일한 내용을 출력param 1args <class 'tuple'> (2, 3)kwargs <class 'dict'> {'a': 1, 'b': 2}인자 p이외의 인자들은 *args를 통해 튜플 형태로 전달되고, 키워드 인자들은 **kward에서 딕셔너리 형태로 전달된다.
Ref
- 파이썬 코딩의 기술
- https://wikidocs.net/22801