[ํ์ด์ฌ] ๋ฐ์ฝ๋ ์ดํฐ(Decorator) ์ฌ์ฉ๋ฒ
์๋ณธ ๊ฒ์๊ธ: https://velog.io/@euisuk-chung/Python-Decorator-Intro
๋ฉ๋ฆฌํฌ๋ฆฌ์ค๋ง์ค ์ฌ๋ฌ๋ถ!!โงโห๐โฉ ํฌ๋ฆฌ์ค๋ง์ค ํธ๋ฆฌ๋ฅผ ์ฅ์ํ ๋, ๊ฐ์ฅ ์ค์ํ ๊ฑด ๋ญ๋ ๋ญ๋ ํด๋ ํธ๋ฆฌ ์์ฒด์ ๋๋ค. ํ์ง๋ง ๋จ์ํ ๋๋ฌด์ ์์ ์ ๊ตฌ, ๋ฆฌ๋ณธ, ์ฅ๋๊ฐ์ ๋ํ๋ฉด ํน๋ณํ ๋ถ์๊ธฐ๋ฅผ ์ฐ์ถํ ์ ์์ฃ . ๋ฐ์ฝ๋ ์ดํฐ๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค! ๊ธฐ๋ณธ ํจ์์ ์ํ๋ ์ฅ์์ ๋ง๋ถ์ฌ์, ํจ์์ ์ ํ๋ฅผ ๊พธ๋ฏธ๊ฑฐ๋ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
์ด๋ฒ ํฌ์คํธ์์๋ ํฌ๋ฆฌ์ค๋ง์ค ํธ๋ฆฌ๋ฅผ ๊พธ๋ฏธ๋ ๊ฒ์ฒ๋ผ, ํจ์์ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋ํด๋ณด๋ ์ฌ๋ฏธ์๋ ์ฌ์ ์ ์์ํด ๋ด ์๋ค. ํจ์ ํธ์ถ ์ ํ๋ก ๋ฉ์์ง๋ฅผ ์ถ๊ฐํ๊ฑฐ๋, ์คํ ์๊ฐ์ ์ธก์ ํ๊ฑฐ๋, ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๊ฑฐ๋, ์ธ์ฆ ์ฒดํฌ๋ฅผ ์ํํ๋ ๋ฑ ๋ค์ํ ๋ฐ์ฝ๋ ์ดํฐ ํ์ฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ฌ๋ฌ๋ถ์ ์ฝ๋๊ฐ ๋์ฑ ๋น๋๊ฒ ๋ ๊ฑฐ์์! โจ
ํ์ด์ฌ์ ๋ฐ์ฝ๋ ์ดํฐ(Decorator)๋ โํจ์๋ ๋ฉ์๋์ ๋์์ ํ์ฅํ๊ฑฐ๋ ์์ ํ ์ ์๋ ๋งค์ฐ ๊ฐ๋ ฅํ ๋๊ตฌโ์ ๋๋ค. ํ์ง๋ง ๊ทธ ๊ฐ๋ ์ด ์์ํ๊ฑฐ๋ ์ฝ๋ ๊ตฌ์กฐ๊ฐ ๋ฏ์ค์ด ์ฒ์ ๋ฐฐ์ฐ๋ ์ฌ๋์๊ฒ๋ ์ด๋ ต๊ฒ ๋๊ปด์ง ์ ์์ต๋๋ค.
- ์ด๋ฒ ๊ธ์์๋ ์ด๋ณด์๋ ์ดํดํ ์ ์๋๋ก ๋ฐ์ฝ๋ ์ดํฐ์ ๊ธฐ๋ณธ ๊ฐ๋ ๊ณผ ํ์ฉ๋ฒ์ ์ฝ๊ณ ๋ช ํํ๊ฒ ์ค๋ช ํ๊ณ , ์ฌ๋ฌ ์์ ๋ฅผ ํตํด ๋ฐ์ฝ๋ ์ดํฐ์ ์ ์ฉ์ฑ์ ๋ณด์ฌ๋๋ฆฌ๊ฒ ์ต๋๋ค.
1. ๋ฐ์ฝ๋ ์ดํฐ๋ ๋ฌด์์ธ๊ฐ์?
์ฐ๋ฆฌ๊ฐ โ๋ฌด์์ธ๊ฐ๋ฅผ decorateํ๋คโ๋ผ๊ณ ํ๋ฉด, โ๋ฌด์์ธ๊ฐ๋ฅผ ์ฅ์ํ๋ค, ๋๋ ๊พธ๋ฏธ๋คโ๋ผ๋ ์๋ฏธ๊ฐ ์์ต๋๋ค.
=> ๋ฐ์ฝ๋ ์ดํฐ(decorator)๋ ๋ง ๊ทธ๋๋ก ํจ์๋ฅผ ๊พธ๋ฉฐ์ฃผ๋ ๋๊ตฌ์ ๋๋ค. ์ฆ, ์ด๋ค ํจ์๊ฐ ์์ ๋ ํด๋น ํจ์๋ฅผ ์ง์ ์์ ํ์ง ์๊ณ ํจ์๋ฅผ ๊พธ๋ฉฐ์ฃผ๊ธฐ ์ํด ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ์ ์:
- ๋ฐ์ฝ๋ ์ดํฐ๋ ํจ์๋ฅผ ์ธ์๋ก ๋ฐ์ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ํ, ์์ ๋ ํจ์๋ฅผ ๋ฐํํ๋ ๊ณ ์ฐจ ํจ์(higher-order function)์ ๋๋ค.
โ ๊ณ ์ฐจ ํจ์(Higher-Order Function)๋ ๋ค์ ๋ ๊ฐ์ง ์กฐ๊ฑด ์ค ํ๋ ์ด์์ ๋ง์กฑํ๋ ํจ์๋ฅผ ๋งํฉ๋๋ค:
- (1) ํจ์๋ฅผ ์ธ์๋ก ๋ฐ์ ์ ์๋ ํจ์
- ๋ค๋ฅธ ํจ์(ํน์ ๋๋ค ํจ์ ๋ฑ)๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ์คํํ๊ฑฐ๋ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ์:
map()
,filter()
,reduce()
๋ฑ์ด ์ด์ ํด๋นํฉ๋๋ค.- (2) ํจ์๋ฅผ ๋ฐํํ ์ ์๋ ํจ์
- ๋ค๋ฅธ ํจ์๋ฅผ ๋ฐํ๊ฐ์ผ๋ก ์์ฑํ๊ฑฐ๋ ๋ฆฌํดํ ์ ์์ต๋๋ค.
(1) ํจ์๋ฅผ ์ธ์๋ก ๋ฐ๋ ์์
1 2 3 4 5 6 7 def apply_function(func, data): return func(data) # ์ฌ์ฉ ์์ def square(x): return x * x result = apply_function(square, 5) # 25 print(result)
apply_function
์func
์ด๋ผ๋ ๋งค๊ฐ๋ณ์๋ก ํจ์๋ฅผ ๋ฐ์ต๋๋ค.- ํธ์ถ ์,
square
๋ผ๋ ํจ์๋ฅผ ๋๊ฒจ์ฃผ๊ณdata
๋ก 5๋ฅผ ์ ๋ฌํ์ฌsquare(5)
๊ฐ ์คํ๋ฉ๋๋ค.
(2) ํจ์๋ฅผ ๋ฐํํ๋ ์์
1 2 3 4 5 6 7 def outer_function(message): def inner_function(): return f"Message: {message}" return inner_function # ์ฌ์ฉ ์์ my_function = outer_function("Hello, World!") print(my_function()) # Message: Hello, World!
outer_function
์inner_function
์ด๋ผ๋ ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.- ๋ฐํ๋
my_function
์ ๋ด๋ถ์inner_function
์ญํ ์ ํ๋ฉฐ, ๋์ค์ ์คํ๋ฉ๋๋ค.
-
๋ฐ์ฝ๋ ์ดํฐ
๋ ๊ณ ์ฐจ ํจ์์ ๋ ๋ฒ์งธ ํน์ง(ํจ์๋ฅผ ๋ฐํํ ์ ์๋ ํจ์)์ ์ด์ฉํฉ๋๋ค.- (์ค๋ช 1) ๋ฐ์ฝ๋ ์ดํฐ๋ ํจ์๋ฅผ ์ธ์๋ก ๋ฐ๊ณ , ๊ทธ ํจ์๋ฅผ ์์ ํ๊ฑฐ๋ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ํจ์๋ฅผ ๋ฐํํ์ฌ ๊ธฐ์กด ํจ์๋ฅผ โ์ฅ์โํฉ๋๋ค.
- (์ค๋ช 2) ๋ฐ์ฝ๋ ์ดํฐ๋ ํจ์๋ฅผ ๋ฐ์์ ๋ด๋ถ์ ์๋ก์ด ํจ์๋ฅผ ์ ์ํ๊ณ , ์ด๋ฅผ ๋ฐํํ๋ ๋ฐฉ์์ผ๋ก ๋์ํฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ธฐ์กด ํจ์์ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
-
์ฅ์ :
- ์ฝ๋ ์์ ์์ด ํจ์์ ๋์์ ๋ณ๊ฒฝํ๊ฑฐ๋ ์ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ์ ๋ถ์ฌํ ์ ์์ต๋๋ค.
- ๋ฐ๋ณต ์ฝ๋๋ฅผ ์ค์ด๊ณ , ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์ ๋๋ค.
์๋ฅผ ๋ค์ด, ํจ์ ํธ์ถ ์ ํ์ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ๊ณ ์ถ๋ค๋ฉด, ํด๋น ์ฝ๋๋ฅผ ๋ชจ๋ ํจ์์ ์ฝ์ ํ์ง ์๊ณ ๋ฐ์ฝ๋ ์ดํฐ๋ก ๊น๋ํ๊ฒ ํด๊ฒฐํ ์ ์์ต๋๋ค.
2. ๋ฐ์ฝ๋ ์ดํฐ ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
2.1 ๊ธฐ๋ณธ ๊ตฌ์กฐ
๋ฐ์ฝ๋ ์ดํฐ์ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
1
2
3
4
5
6
7
def my_decorator(func): # func: ๊พธ๋ฏธ๊ณ ์ ํ๋ ํจ์
def wrapper():
print("Before the function is called")
func() # ์๋ ํจ์ ์คํ
print("After the function is called")
return wrapper # ์์ ๋ ํจ์ ๋ฐํ
my_decorator(func)
: ๋ฐ์ฝ๋ ์ดํฐ๋ก ์ฌ์ฉ๋ ํจ์์ ๋๋ค.- ์ด ํจ์๋ ๋ค๋ฅธ ํจ์๋ฅผ ๋งค๊ฐ๋ณ์(
func
)๋ก ๋ฐ์, ์๋ ํจ์(func)์ ๋์์ ๊ฐ์ธ๋wrapper
ํจ์๋ฅผ ์ ์ํ๊ณ ๋ฐํํฉ๋๋ค. wrapper()
: ์๋ ํจ์(func
) ํธ์ถ ์ ํ์ ์ถ๊ฐ ๋์์ ์ฝ์ ํ๋ ํจ์์ ๋๋ค.
- ์ด ํจ์๋ ๋ค๋ฅธ ํจ์๋ฅผ ๋งค๊ฐ๋ณ์(
2.2 ๋ฐ์ฝ๋ ์ดํฐ ์ ์ฉ
๋ฐ์ฝ๋ ์ดํฐ๋ @
๋ฅผ ์ฌ์ฉํด ๊ฐํธํ๊ฒ ์ ์ฉํ ์ ์์ต๋๋ค.
1
2
3
4
5
6
@my_decorator
def say_hello():
print("Hello, World!")
say_hello()
@my_decorator
:say_hello
ํจ์์my_decorator
๋ฅผ ์ ์ฉํฉ๋๋ค.say_hello
๋ ์ด์ my_decorator(say_hello)
๊ฐ ๋ฐํํ๋wrapper
ํจ์๋ก ๋์ฒด๋ฉ๋๋ค.
- ๊ฒฐ๊ณผ์ ์ผ๋ก
say_hello()
๋ฅผ ํธ์ถํ๋ฉดwrapper()
๊ฐ ์คํ๋ฉ๋๋ค.
์ฆ, ์ ์ฝ๋๋ ์๋ ์ฝ๋์ ๋์ผํ๊ฒ ๋์ํฉ๋๋ค:
1
2
3
say_hello = my_decorator(say_hello)
say_hello()
- ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์์ฒ๋ผ ์๋์ผ๋ก ํจ์์ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ ์ฉํด๋ ๋์ผํ ๊ฒฐ๊ณผ๊ฐ ๋์ต๋๋ค.
- ์๋
say_hello
ํจ์๋my_decorator
๋ฅผ ํตํด ๊ฐ์ธ์ธwrapper
๋ก ๋์ฒด๋ฉ๋๋ค.
2.3 ์คํ ๊ฒฐ๊ณผ
1
say_hello()
-
ํจ์ ํธ์ถ ํ๋ฆ:
wrapper
ํจ์๊ฐ ์คํ๋ฉ๋๋ค.print("Before the function is called")
๊ฐ ์คํ๋ฉ๋๋ค.- ์๋
say_hello
ํจ์ (func
)๊ฐ ์คํ๋ฉ๋๋ค. ์ฌ๊ธฐ์print("Hello, World!")
๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค. print("After the function is called")
๊ฐ ์คํ๋ฉ๋๋ค.
-
์ต์ข ์ถ๋ ฅ:
1
2
3
Before the function is called
Hello, World!
After the function is called
3. ๋ฐ์ฝ๋ ์ดํฐ ์์ ๋ก ๋ฐฐ์ฐ๊ธฐ
3.1 ๊ฐ๋จํ ๋ฐ์ฝ๋ ์ดํฐ ์์
ํจ์ ํธ์ถ ์ ํ์ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋ง๋ค์ด ๋ด ์๋ค.
- ์ฒซ ๋ฒ์งธ ์์ ๋ ์์ 2๋ฒ์์ ๋ณธ ์์์ ์ ์ฌํ ์ ํ์ ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
def my_decorator(func):
def wrapper():
print("Before the function is called")
func()
print("After the function is called")
return wrapper
@my_decorator
def greet():
print("Hello!")
greet()
-
my_decorator
:- ์ด ํจ์๋ ์๋ ํจ์๋ฅผ ๊ฐ์ธ๋ ์ญํ ์ ํฉ๋๋ค. ํธ์ถ ์ ํ์ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ์ฌ ํจ์ ๋์์ ๋ณด๊ฐํฉ๋๋ค.
-
greet
:- ๋จ์ํ โHello!โ๋ฅผ ์ถ๋ ฅํ๋ ํจ์์ด๋,
@my_decorator
๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ํตํด ํธ์ถ ์ ํ์ ๋ฉ์์ง๊ฐ ์ถ๊ฐ๋ก ์ถ๋ ฅ๋ฉ๋๋ค.
- ๋จ์ํ โHello!โ๋ฅผ ์ถ๋ ฅํ๋ ํจ์์ด๋,
์ถ๋ ฅ ๊ฒฐ๊ณผ:
1
2
3
Before the function is called
Hello!
After the function is called
3.2 ์ธ์์ ๋ฐํ๊ฐ ์ฒ๋ฆฌ
๋ฐ์ฝ๋ ์ดํฐ๋ *args
์ **kwargs
๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ํ ์ธ์์ ๋ฐํ๊ฐ์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Function is about to execute")
result = func(*args, **kwargs) # ์๋ ํจ์ ํธ์ถ
print("Function has finished executing")
return result
return wrapper
@my_decorator
def add(a, b):
return a + b
print(add(3, 4))
wrapper
: ์ธ์์ ๋ฐํ๊ฐ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด*args
์**kwargs
๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ก ์ธํด ๋ค์ํ ํํ์ ํจ์ ํธ์ถ์ ์ง์ํ ์ ์์ต๋๋ค.add
: ๋ ์ซ์์ ํฉ์ ๋ฐํํ๋ ํจ์์ ๋๋ค. ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ํตํด ํธ์ถ ์ ํ์ ๋ฉ์์ง๊ฐ ์ถ๋ ฅ๋๋ฉฐ, ๊ฒฐ๊ณผ๊ฐ๋ ๋ฐํ๋ฉ๋๋ค.
์ถ๋ ฅ ๊ฒฐ๊ณผ:
1
2
3
Function is about to execute
Function has finished executing
7
4. ๋ฐ์ฝ๋ ์ดํฐ ํ์ฉ ์์
4.1 ๋ก๊น ๋ฐ์ฝ๋ ์ดํฐ
์ด๋ค ํจ์๊ฐ ํธ์ถ๋ ๋ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๊ณ ์ถ์ ๋ ์ ์ฉํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import logging
logging.basicConfig(level=logging.INFO)
def log_decorator(func):
def wrapper(*args, **kwargs):
logging.info(f"Calling {func.__name__} with {args} and {kwargs}")
result = func(*args, **kwargs)
logging.info(f"{func.__name__} finished executing")
return result
return wrapper
@log_decorator
def multiply(a, b):
return a * b
print(multiply(5, 3))
log_decorator
: ํจ์ ํธ์ถ ์ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํฉ๋๋ค. ์ด๋ก ์ธํด ๋๋ฒ๊น ์ด๋ ํจ์ ํธ์ถ ์ถ์ ์ ์ ์ฉํฉ๋๋ค.multiply
: ๋ ์ซ์๋ฅผ ๊ณฑํ๋ ํจ์๋ก, ํธ์ถ ์ ๋ก๊ทธ๊ฐ ์๋์ผ๋ก ๊ธฐ๋ก๋ฉ๋๋ค.
์ถ๋ ฅ ๊ฒฐ๊ณผ:
1
2
3
INFO:root:Calling multiply with (5, 3) and {}
INFO:root:multiply finished executing
15
4.2 ์คํ ์๊ฐ ์ธก์ ๋ฐ์ฝ๋ ์ดํฐ
ํจ์ ์คํ์ ๊ฑธ๋ฆฐ ์๊ฐ์ ์ธก์ ํ๋ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋ง๋ค์ด ๋ด ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import time
def timing_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time() # ์์ ์๊ฐ ๊ธฐ๋ก
result = func(*args, **kwargs)
end_time = time.time() # ์ข
๋ฃ ์๊ฐ ๊ธฐ๋ก
print(f"{func.__name__} took {end_time - start_time:.4f} seconds to execute")
return result
return wrapper
@timing_decorator
def slow_function():
time.sleep(2)
print("Finished sleeping")
slow_function()
timing_decorator
: ํจ์ ์คํ ์์๊ณผ ์ข ๋ฃ ์๊ฐ์ ๊ธฐ๋กํ์ฌ ์คํ ์๊ฐ์ ์ธก์ ํฉ๋๋ค.slow_function
: 2์ด๊ฐ ๋ฉ์ถ ๋ค ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋ ํจ์๋ก, ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ํตํด ์คํ ์๊ฐ์ด ์ธก์ ๋ฉ๋๋ค.
์ถ๋ ฅ ๊ฒฐ๊ณผ:
1
2
Finished sleeping
slow_function took 2.0002 seconds to execute
4.3 ์ธ์ฆ ๋ฐ์ฝ๋ ์ดํฐ
์ฌ์ฉ์์ ์ธ์ฆ ์ํ๋ฅผ ํ์ธํ๊ณ , ์ธ์ฆ๋์ง ์์ผ๋ฉด ์๋ฌ๋ฅผ ๋ฐ์์ํค๋ ๋ฐ์ฝ๋ ์ดํฐ์ ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def authenticate_decorator(func):
def wrapper(user, *args, **kwargs):
if not user.get("is_authenticated"):
raise PermissionError("User not authenticated")
return func(user, *args, **kwargs)
return wrapper
@authenticate_decorator
def view_profile(user):
print(f"User profile: {user['name']}")
user = {"name": "Alice", "is_authenticated": True}
view_profile(user)
unauth_user = {"name": "Bob", "is_authenticated": False}
view_profile(unauth_user) # PermissionError ๋ฐ์
authenticate_decorator
: ์ฌ์ฉ์์ ์ธ์ฆ ์ํ๋ฅผ ํ์ธํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ธ์ฆ๋์ง ์์ ์ฌ์ฉ์์ ๋ํด ์์ธ๋ฅผ ๋ฐ์์ํต๋๋ค.view_profile
: ์ฌ์ฉ์ ํ๋กํ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๋ ํจ์์ ๋๋ค. ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ํตํด ์ธ์ฆ ์ํ๋ฅผ ํ์ธํฉ๋๋ค.
์ถ๋ ฅ ๊ฒฐ๊ณผ:
1
2
3
4
User profile: Alice
Traceback (most recent call last):
...
PermissionError: User not authenticated
5. ๊ณ ๊ธ ์ฃผ์ : functools.wraps
๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ ํจ์์ ์ด๋ฆ(__name__
)๊ณผ ๋ฌธ์ ๋ฌธ์์ด(__doc__
)์ด ๊ฐ์ธ๋ ํจ์(wrapper)๋ก ๋ฎ์ฌ ์๋ ํจ์์ ์ ๋ณด๋ฅผ ์๊ฒ ๋ฉ๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด functools.wraps
๋ฅผ ์ฌ์ฉํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs)
print("After function call")
return result
return wrapper
@my_decorator
def my_function():
"""This is my function."""
print("Hello!")
print(my_function.__name__) # my_function
print(my_function.__doc__) # This is my function.
wraps
:functools
์ ์ ํธ๋ฆฌํฐ๋ก, ๋ฐ์ฝ๋ ์ดํฐ ์ ์ฉ ํ์๋ ์๋ ํจ์์ ๋ฉํ๋ฐ์ดํฐ(__name__
,__doc__
)๋ฅผ ์ ์ง์์ผ์ค๋๋ค.my_function
: ๊ฐ๋จํ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋ ํจ์๋ก, ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ํตํด ํธ์ถ ์ ํ์ ๋ฉ์์ง๊ฐ ์ถ๊ฐ๋ฉ๋๋ค.
์ถ๋ ฅ ๊ฒฐ๊ณผ:
1
2
3
4
5
Before function call
Hello!
After function call
my_function
This is my function.
๐งฉ functools.wraps
functools.wraps
๋ Python์์ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์์ฑํ ๋, ์๋ ํจ์์ ๋ฉํ๋ฐ์ดํฐ(์: ํจ์ ์ด๋ฆ, ๋ฌธ์ ๋ฌธ์์ด ๋ฑ)๋ฅผ ๋ณด์กดํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ์ ํธ๋ฆฌํฐ์ ๋๋ค.
- ์ผ๋ฐ์ ์ผ๋ก ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ ์ฉํ๋ฉด ์๋ ํจ์์ ์ด๋ฆ(name)๊ณผ ๋ฌธ์ ๋ฌธ์์ด(doc)์ด ๋ฐ์ฝ๋ ์ดํฐ๋ก ๋์ฒด๋ ํจ์(์ฃผ๋ก wrapper ํจ์)๋ก ๋ณ๊ฒฝ๋ฉ๋๋ค.
- ์ด๋ก ์ธํด ๋๋ฒ๊น ์ด๋ ํจ์์ ๋ฉํ์ ๋ณด๋ฅผ ํ์ธํ๊ธฐ ์ด๋ ค์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ์ฃผ์ ๊ธฐ๋ฅ
- ์๋ ํจ์ ์ด๋ฆ ์ ์ง: ๋ฐ์ฝ๋ ์ดํฐ๊ฐ ์ ์ฉ๋ ํจ์๋ ์๋ ํจ์ ์ด๋ฆ์ผ๋ก ํ์๋ฉ๋๋ค.
- ๋ฌธ์ ๋ฌธ์์ด ๋ณด์กด: ์๋ ํจ์์ Docstring์ด ์ ์ง๋ฉ๋๋ค.
- ๊ธฐํ ๋ฉํ๋ฐ์ดํฐ ๋ณด์กด: module, annotations, dict ๊ฐ์ ์์ฑ๋ ์ ์ง๋ฉ๋๋ค.
6. ๋ฐ์ฝ๋ ์ดํฐ ์ค์ฒฉ
๋ฐ์ฝ๋ ์ดํฐ๋ ์ฌ๋ฌ ๊ฐ๋ฅผ ๋์์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์ด๋ ์ ์ฉ ์์๋ ๊ฐ์ฅ ๊ฐ๊น์ด ๋ฐ์ฝ๋ ์ดํฐ๋ถํฐ ์คํ๋ฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def decorator1(func):
def wrapper():
print("Decorator 1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2")
func()
return wrapper
@decorator1
@decorator2
def hello():
print("Hello!")
hello()
decorator1
: ๊ฐ์ฅ ๋ฐ๊นฅ์ชฝ์์ ์คํ๋๋ ๋ฐ์ฝ๋ ์ดํฐ์ ๋๋ค.decorator2
: ๊ฐ์ฅ ์์ชฝ์์ ์คํ๋๋ ๋ฐ์ฝ๋ ์ดํฐ์ ๋๋ค.hello
: ๋ฐ์ฝ๋ ์ดํฐ ์ค์ฒฉ์ ํตํด ํธ์ถ ์์์ ๋ฐ๋ผ ๋ฉ์์ง๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
์ถ๋ ฅ ๊ฒฐ๊ณผ:
1
2
3
Decorator 1
Decorator 2
Hello!
7. ๊ฒฐ๋ก
๋ฐ์ฝ๋ ์ดํฐ๋ ์ฒ์์ ๋ค์ ์ด๋ ต๊ฒ ๋๊ปด์ง ์ ์์ง๋ง, ๊ทธ ์๋ฆฌ๋ฅผ ์ดํดํ๋ฉด ๋งค์ฐ ์ ์ฉํ ๋๊ตฌ์ ๋๋ค. ํนํ ๋ฐ๋ณต์ ์ธ ์์ ์ ์ค์ด๊ณ , ์ฝ๋๋ฅผ ๊น๋ํ๊ณ ํจ์จ์ ์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค.
๐ SUMMARY
๋ฐ์ฝ๋ ์ดํฐ๋ ํจ์๋ฅผ ๊พธ๋ฉฐ์ฃผ๋ ๋๊ตฌ์ ๋๋ค.
@
๋ฅผ ์ฌ์ฉํด ๊ฐ๋จํ๊ฒ ์ ์ฉํ ์ ์์ต๋๋ค.๋ค์ํ ํ์ฉ๋ฒ(๋ก๊น , ์คํ ์๊ฐ ์ธก์ , ์ธ์ฆ ๋ฑ)์ผ๋ก ์ฝ๋๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
functools.wraps
๋ฅผ ์ฌ์ฉํด ์๋ ํจ์ ์ ๋ณด๋ฅผ ๋ณด์กดํ์ธ์.
์ค๋์ ํฌ๋ฆฌ์ค๋ง์ค ํน์ง์ผ๋ก ๋ฐ์ฝ๋ ์ดํฐ ๊ฐ๋ ์ ์ ๋ฆฌํด๋ณด์๋๋ฐ์! ์ ๋ ์ค์ ์ ์ฌ์ฉํ์ง๋ ๋ชปํ๋ ํธ์ด์ง๋ง ๋ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ณด๋ฉด ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฐ๋ ์ฝ๋๋ค์ด ๋ง์์ ์ค์ํ ๊ฐ๋ ์ด๋๋๋ค!! ๐
์ด์ ์ง์ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋ง๋ค์ด ๋ณด๊ณ , ๋ค์ํ ํจ์์ ์ ์ฉํด ๋ณด์ธ์!
๋ฐ์ฝ๋ ์ดํฐ์ ๋งค๋ ฅ์ ๋น ์ง๊ฒ ๋ ๊ฒ์ ๋๋ค.
์ค๋๋ ์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค :)