*args and **kwargs in Python
두개 모두 가변인자를 위한 변수이다.
*args(키워드가 없는 인자, arguemnts)
- 함수에 가변 값을 넣어줄 때 사용한다. 즉 인자의 값의 길이에 제한 없이 사용할 수 있다.
- 이전에 정의한 값보다 더 많은 인자들을 넣을 때 사용한다.
- 인자의 값이 튜플 형태로 저장된다.
예시
def foo(*args):
for a in args:
print(a)
foo(1)
# 1
foo(1,2,3)
# 1
# 2
# 3
**kwargs(키워드가 있는 인자, keyword arguments)
- 인자의 값이 딕셔너리 형태로 저장된다.
- 더블 스타(**)를 사용하는 이유는 키워드 인자를 통해 인자를 전달할 수 있기 때문이다. 이를 통해 어떤 수의 키워드 인자라도 전달할 수 있다.
예시
def bar(**kwargs):
for a in kwargs:
print(a, kwargs[a])
bar(name='one', age=27)
# name one
# age 27
다른 예시
def table_things(**kwargs):
for name, value in kwargs.items():
print(f'{name} = {value}')
table_things(apple='fruit', cabbage='vegetable')
사전에 딕셔너리를 만들지 않아도 함수에서 넣어줄 때 담아주면 키값도 같이 가져온다.
위치 인자와 키워드 인자
첫번째로 무엇이 위치 인자와 키워드 인자를 이해해 보자.
아래는 위치 인자와 함수 정의 예시이다.
def test(a, b, c):
print(a)
print(b)
print(c)
test(1,2,3)
#output:
1
2
3
1, 2, 3으로 받은 값을 하나씩 출력하는 함수이다.
이 함수는 위치 인자를 정의하고 있다. 키워드와/이름이 지어진 인자들 또한 호출할 수 있다.
def test(a, b, c):
print(a)
print(b)
print(c)
test(a=1, b=2, c=3)
#output:
1
2
3
위처럼 지정하여 인자를 지정해 주어도 결과는 동일하다.
이제 키워드 인자의 함수 정의 예시를 공부해 보자.
def test(a=0, b=0, c=0):
print(a)
print(b)
print(c)
print('-------------------------')
test(a=1,b=2,c=3)
#output:
1
2
3
-------------------------
또한 위치인자의 함수들 또한 호출할 수 있다. 실행결과는 위와 같다.
이제 우리는 위치 인자와 키워드 인자를 사용하는 함수 정의에 대해 이해할 수 있다.
여기까지는 함수를 호출할 때 들어올 인자 수를 3개로 지정해 주었다.
* 연산자와 ** 연산자
이제 '*' 연산자와 '**' 연산자를 공부해 보자.
이러한 연산자는 두 가지 영역에서 사용할 수 있다.
a) 함수 호출
b) 함수 정의
함수 호출에서 '*' 연산자와 '**' 연산자의 사용예제를 살펴보고 그 후에 이에 대해 논의해 보자.
def sum(a, b): # 인자들을 다음과 같이 받는다. -> sum(1,2) or sum(a=1,b=2)
print(a + b)
my_tuple = (1, 2) # 튜플
my_list = [1, 2] # 리스트
my_dict = {'a': 1, 'b': 2} # 딕셔너리
# Let us unpack data structure of list or tuple or dict into arguments with help of '*' operator
# '*'오퍼레이터의 인자를 활용하여 리스트 또는 튜플 또는 딕셔너리의 데이터 구조를 알아보자.
sum(*my_tuple) # '*'를 사용한 튜플실행결과는 sum(1,2)와 같다.
sum(*my_list) # '*'를 사용한 리스트 실행 결과는 sum(1,2)의 결과와 같다.
sum(**my_dict) # '**'를 사용한 딕셔너리 실행 결과는 sum(a=1, b=2)와 같다.
# output is 3 in all three calls to sum function.
# 3개의 함수에서 모두 3의 결과가 나온다.
위에서 인자 2개를 받아 더한 값을 반환하는 함수 sum(a, b)를 만든다.
두개의 값이 각각 담긴 튜플, 리스트, 딕셔너리를 만들었다. (my_tuple, my_list, my_dict)
같은 함수에 *을 붙여 튜플과 리스트를 각각 넣고, **을 붙여 딕셔너리를 넣는다.
위에서 설명했던 것처럼 *는 리스트는 튜플 형태로 값을 전달하고, **를 붙이면 딕셔너리 형태로 값을 전달한다.
→ 그래서 기억해야 할 것은
‘*’연산자와 ‘**’연산자는 함수를 호출하는데 사용된다는 것이다.
'*' 연산자는 리스트나 튜플과 같은 데이터 구조체를 함수 정의에서 필요한 인자들로 분해한다.
'**' 연산자는 딕셔너리를 함수 정의에서 필요한 인자들로 분해한다.
이제 ‘*’연산자를 함수 정의에서 사용하는 방법을 보자.
예시
def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))
sum = 0
for a in args:
sum+=a
print(sum)
sum(1,2,3,4) #positional args sent to function sum
#output
10
위의 sum(*args) 함수에서는 *args로 인자에 제한 없이 값들을 튜플로 받는다.
그래서 1, 2, 3, 4는 for문을 돌면서 값들을 더하고, 더한 값 10을 출력한다.
요약: ‘*’연산자의 정의 기능은 튜플 형식으로 정보를 받는다.
또다른 예시1
def myFun(arg1, *argv):
print("첫번째 인자:", arg1)
for arg in argv:
print("그 다음으로 받은 인자 :", arg)
myFun('안녕하세요', '오늘은', '2023년 6월', '막바지입니다', '굉장히', '습하네요.')
'''
[출력]
첫번째 인자: 안녕하세요
그 다음으로 받은 인자 : 오늘은
그 다음으로 받은 인자 : 2023년 6월
그 다음으로 받은 인자 : 막바지입니다
그 다음으로 받은 인자 : 굉장히
그 다음으로 받은 인자 : 습하네요.
'''
두번째 인자에 *을 붙여서 받으면, 첫 번째 인자만 그로 들어가고 그 뒤로는 *argv로 받는다.
또다른 예시2
def print_everything(*args):
for count, thing in enumerate(args):
print( f'{count}. {thing}')
print_everything('apple', 'banana', 'cabbage')
enumerate를 활용하여 같이 쓸 수도 있다.
이제, 함수 정의에서 ‘**’이 사용되는 예시를 보자.
def sum(**args):
# '**'뒤에 키워드 연산을 입력하면 딕셔너리 자료구조로 저장된다 = def sum(a:1,b:2,c:3,d:4}) 와 같다.
sum=0
for k,v in args.items():
sum+=v
print(sum)
sum(a=1,b=2,c=3,d=4) # sum() 함수로 보내진다.
#output
10
위의 sum(**args) 함수에서는 sum() 함수 안에 args라는 딕셔너리를 만들고, 그 안에 1, 2, 3, 4값을 넣는다.
*와 다르게 파라미터 명을 같이 보낼 수 있다.
‘**’ 연산은 딕셔너리 형태로 인자들을 받는다.
함수 호출에서 '*'는 튜플이나 리스트 구조체를 함수 정의에서 받을 위치나 키워드 인자로 언팩(unpack)한다.
함수 호출에서 '**'는 딕셔너리 구조체를 함수 정의에서 받을 위치나 키워드 인자로 언팩한다.
함수 정의에서 '*'는 위치 인자를 튜플로 패킹(pack)한다.
함수 정의에서 '**'는 키워드 인자를 딕셔너리로 패킹한다.
(여기서 패킹은 튜플로 값을 묶는다는 뜻이고, 언패킹은 튜플로 묶인 값을 푼다는 뜻이다.)
더 설명하자면,
함수 정의에서 *는 위치 인자를 튜플로 패킹한다.
이는 함수를 정의할 때 인자 앞에 *를 붙이면 해당 인자들이 튜플로 묶여서 함수 내에서 사용된다.
이렇게 하면 함수를 호출할 때 인자의 개수가 가변적일 때 유용하다.
함수 호출에서 **는 딕셔너리 구조체를 함수 정의에서 받을 위치나 키워드 인자로 언팩한다.
이는 호출할 함수에서 받은 딕셔너리를 개별 인자로 쪼개서 함수에 전달하는 것을 의미한다.
이를 통해 함수 호출 시 개별 인자를 지정하는 것보다 더 많은 인자를 쉽게 전달할 수 있다.
함수 정의에서 **는 키워드 인자를 딕셔너리로 패킹합니다.
이는 함수를 정의할 때 인자 앞에 **를 붙이면 해당 인자들이 딕셔너리로 묶여서 함수 내에서 사용된다.
이렇게 하면 함수를 호출할 때 인자의 이름과 값을 함께 전달할 수 있어서 가독성이 높아진다.
*args and **kwargs의 사용
def time_cal(func):
def wrapper(*args, **kwargs):
start=time.time()
time.sleep(1)
result = func(*args, **kwargs)
end= time.time()
print(func.__name__+ ' took ' + str((end-start)*1000) + ' milli seconds')
return result
return wrapper
*args와 **kwargs는 데코레이터를 만들 때 유용하게 사용된다.
위의 코드는 함수를 실행할 때 몇 초 걸리는지 알려주는 데코레이터이다.
사용 방법은 함수를 만들 때 @를 붙인 후 데코레이터 함수 이름을 적어주면 된다.
사용 예시
arr = [5, 17, 31, 34, 40, 50, 61, 71, 79, 87, 97, 100]
@time_cal
def sample_func(arr, target):
"""일일히 비교"""
for idx, i in enumerate(arr):
if i == target:
print(idx)
break
sample_func(arr, 50)
# 5
sample_func took 0.0 milli seconds
참고 사이트: https://stackoverflow.com/questions/3394835/use-of-args-and-kwargs
'개발공부 > Python' 카테고리의 다른 글
[Python] requirements.txt 생성하고 패키지 관리하기 (0) | 2023.07.28 |
---|---|
[Python] 함수 실행 시간 측정하기 - time() 사용한 여러가지 방법 (0) | 2023.06.27 |
[Matplotlib] 그래프에 옵션 추가 - title(), legend(), color(), marker(), linestyle() (0) | 2023.06.23 |
[Python] List Comprehension(리스트 컴프리헨션) 공부와 Nato 알파벳 음성기호 만들기 (0) | 2023.06.10 |
[Matplotlib] Matplotlib, pandas로 k-pop 그룹 데이터 분석해보기 (1) | 2023.06.08 |