*args
함수의 인자가 몇개인지 모를 때 사용
#example
def add(a, b, c):
add(a+b+c)
add(2, 3, 4)
# Output
9
일반적인 함수는 위와 같이 parameter 갯수가 지정이 된다.
그러나 일단 parameter 갯수가 몇개인지 모를 수 있을 때도 있다.
이럴 때를 위해서 존재하는 것이 arguments(*args
) 이다.
일반적으로 *args
라고 쓰지만, *
뒤에 어떤게 와도 상관없다.
*hiphop
, *love
, *munequita
등 무엇이든 가능하다.
방법은 그냥 간단하게 함수의 parameter를 넣을 자리에 *args
를 넣으면 된다.
# example
def add(*args):
result = 0
for i in args:
result += i
print(result)
add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
# Output
55
*args
에 집어넣은 value는 튜플 형태가 된다.
예를 들어 위에서 1~10까지 넣었다면, add
함수 안에 *args
라는 튜플이 생기고, 그 안에 (1, 2, 3, .., 10)
까지 튜플 형식으로 추가가 되는 것이다.
**kwargs
함수의 인자가 몇개인지 모를 때 사용
*args
와 동일한 로직이며, 튜플이 아닌 딕셔너리 형태로 저장된다는 점이 다르다.
*args
와 똑같이 **kwargs
말고도 다양한 이름으로 생성 가능하다.
(**rock
, **peace
, **jazz
등..)
# example
def movie_info(**kwargs):
print(kwargs)
movie_info(name='Cold War', genre='Romance')
#Output
{'name': 'Cold War', 'genre': 'Romance'}
위에서처럼, movie_info
함수에 **kwargs
를 준 후, 함수를 호출 할때 name
과 genre
parameter를 각각 지정한 후 value를 나열해주면,
name
과 genre
가 key
, 할당된 value
들이 value
와 같은 딕셔너리 형식으로 출력이 된다.
*args
와 **kwargs
의 동시 사용*args
와 **kwargs
는 동시에 사용할 수 있다.
*args
는 튜플의 형태로,
**kwargs
는 딕셔너리의 형태로로 출력이 된다.
# example
def info(*args, **kwargs):
return(f"*args is {args}, and **kwargs is {kwargs}")
print(info("Love", 6, True, name='Cold War', genre='Romance'))
# Output
*args is ('Love', 6, True), and **kwargs is {'name': 'Cold War', 'genre': 'Romance'}
*args
로 지정해준 Love
(string), 6
(number), True
(boolean)은 튜플 형태
→ ('Love', 6, True)
**kwargs
로 지정해준 name='Cold War'
, genre='Romance'
는 딕셔너리 형태
→ {'name': 'Cold War', 'genre': 'Romance'}
함수 안에서 함수를 선언하는 것이 가능
중첩 함수는 상위의 부모 함수 안에서만 호출이 가능하므로 부모 함수를 벗어나서 호출 될 수 없다.
# example_1
def parent_function():
def child_function():
return 'Yo'
print(parent_function())
# Output
None
부모함수parent_function()
이 아닌 중첩함수 child_function()
에 return
값을 준 것이므로, 부모 함수를 호출한다고 해도 정의된 return 값이 없기에 None
이 호출
# example_2
def parent_function():
def child_function():
return 'Yo'
return child_function()
print(parent_function())
# Output
Yo
이번엔 부모함수parent_function()
의 return
값으로 자식함수child_function()
를 주었으니, 자식함수의 return
값을 부모함수 외부에서 호출할 수 있다.
데코레이터라는 말 그대로 어떤 함수가 실행되기 전 무조건 실행되도록 하기 위해 '꾸며준다' 라고 생각하면 된다.
특정 함수를 실행하기 전에 강제적으로 다른 함수가 먼저 실행된후 실행되도록 하는 강제성을 제공하는 기능이다.
예를 들어,
모든 가사 문장 뒤에 'yo yo!'를 붙이는 함수를 문장별로 만들어 본다고 하자.
문장을 만들때마다 뒤에 'yo yo!'를 붙일 수도 있지만, 이 경우엔 굉장히 귀찮은 작업이 될 것이다.
이때 데코레이터를 이용하면 굉장히 쉽게 할 수 있다.
# example
def yo_maker(func):
def wrapper(*args, **kwargs):
return f'{func(*args, **kwargs)}, yo yo!'
return wrapper()
@yo_maker
def lyrics():
return "This is hiphop"
print(lyrics)
# Output
This is hiphop, yo yo!
쉽게 생각해서, yo_maker(func)
의 func
자리에 lyrics()
함수가 들어가서 yo_maker(lyrics)
의 형태가 되도록 해주는 것이다.
yo_maker(func)
선언wrapper()
선언wrapper
함수가 return
되면 func
함수 뒤에 'yo yo!'
가 나오도록 설정lyrics
함수를 만들 때 yo_maker
함수를 데코레이터로 설정lyrics
함수가 리턴되기 전에 yo_maker
함수부터 리턴yo_maker(lyrics)
의 형태*args
와 **kwargs
차이에 대한 이해이제 조금 명확하게 두 가변인자에 대한 차이를 알 수 있을 것 같다.
*args
는 튜플 형태
**kwargs
는 딕셔너리 형태
항상 기억하자!
대강 Decorator가 어떤 기능인지 이해하고 위와 같이 정리하였으니, 내가 원하는 형태로 데코레이터를 설정하기 위해서는 아직도 애매모호한 것이 많은 듯 하다..
현업에서 어떠한 형태로 많이 쓰이는 지를 알아보고 싶다.
참고
https://legitcode267.tistory.com/13
https://dojang.io/mod/page/view.php?id=2427