*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 |
댓글