오늘은 파이썬의 decorator 개념에 대해 공부해보자!
파이썬에서 함수를 장식하는 것!을 데코레이터라고 할 수 있다.
@
를 통해 사용하며, 이미 완성된 함수에 함수를 수정하지 않고 추가 기능을 구현할 때 사용한다. 데코레이터는 ['장식자'] 라고 불리기도 한다.
@ decorator
def 함수 이름():
코드
🔆 매개변수와 반환값이 없는 함수 데코레이터 만들기
def trace(func): # 호출할 함수를 매개변수로 받음
def wrapper(): # 호출할 함수를 감싸는 함수
print (func.__name__,'함수시작') # __.name.__ 을 통해 이름 입력
func() # 함수 호출
print (func.__name__,'함수끝')
return wrapper # wrapper 함수 반환
trace_hello = trace(hello) # 데코레이터에 호출할 함수 넣음
trace_hello() # 반환된 함수를 호출
@ trace # 데코레이터 사용
def hello(): # 함수로 호출한 hello가 상단 trace 함수 func() 자리에 들어감
print ('hello')
hello() # 함수 그대로 출력
중첩함수 (함수안의 함수)를 정의해준 후, @ 를 활용해 함수의 이름을 불러주고, print하면
상단의 trace 함수의 로직을 통해 다음과 같은 문구가 출력된다.
hello 함수 시작
hello
hello 함수 끝
데코레이터는 여러개 적용도 가능하나, 위에서 아래 순으로 실행된다.
🔆 매개변수와 반환값을 처리하는 함수 데코레이터 만들기
def practice(func):
def pracWrapper(a,b): # 호출할 함수 add(a,b)의 매개변수와 똑같이 지정
r = func(a,b) # func에 매개변수 a,b를 넣어서 호출하고 반환값에 저장
print('{0}(a={1},b={2}) -> {3}.' .format(func.__name__,a,b,r)) # 매개 변수와 변환값 출력
return r # func값 반환
return pracWrapper # pracWrapper 값 반환
@practice # @ 데코레이터 사용
def add(a,b): # 두개의 변수가 있다.
return a + b # a와 b를 더해라!
print(add(10,20))
pracWrapper 함수에서 return r
해주지 않으면 add 함수를 호출해도 반환 값이 나오지 않기 때문에 해당 부분을 유의해야 한다.
✔️ 만약, func의 반환값을 출력할 필요가 없다면?
: return func(a,b)
의 형태로 바로 함수를 호출하고 반환해도 된다.
🔆 매개변수가 고정되지 않은 함수 처리하기
def notFix(func):
def Wrapper(*args, **kwargs): # 가변인수함수로 만들어준다.
r = func(*args, **kwargs) # func에 args, kwargs를 넣어준다
print('{0}(args={1}, kwargs={2})-> {3}'.format(func.__name__, args,kwargs,r)) # 매개변수의 반환값을 출력한다
return r # func의 반환값을 반환
return Wrapper # Wrapper함수 반환
@notFix # 데코레이터 사용하기
def get_Max(*args) # 위치 인수를 사용하는 가변인수 함수
return Max(args)
@notFix
def get_Min(**kwargs): # 키워드 인수를 사용하는 가변인수 함수
return Min(kwargs.values())
print(get_Max(10,20)) # 20 출력
print(get_Min(x=10,y=30, z=50)) # 10 출력
하단에 만들어준 get_Max
,get_Min
함수는 각각 가변 인수 함수이므로, 데코레이터도 가변 인수 함수로 만들어야 한다.
위치 인수와 키워드 인수 모두를 받을 수 있도록 args, kwargs를 지정해주어야 한다.
args는 튜플, kwargs는 딕셔너리 형태로 출력이 된다.
그러므로, func에 넣을 때는 언패킹 해서 넣어야 한다!
이렇게 만든다면, 가변함수가 아닌 일반 함수에도 데코레이터 사용이 가능하다 -!
다음은, 클래스에 데코레이터를 만드는 방법이다.
이 방법을 잘 익혀야 현재 짜고 있는 View에 데코레이터를 적용할 수 있다!!!!!!!!!
🔆 함수의 시작과 끝을 출력하는 데코레이터 - class.ver
class Trace:
def __init__(self,func): # 호출할 함수를 인스턴스의 초깃값으로 받음
self.func = func # 호출할 함수를 속성 func에 저장
def __call__(self): # 인스턴스를 호출하기 위해 만듬
print(self.func.__name__,'함수 시작') # __name__으로 함수 이름 출력
self.func() # 속성 func에 저장된 함수 호출
print(self.func.__name__,'함수 끝')
@Trace
def hello():
print('hello')
hello() # 함수 그대로 호출
먼저 __init__
method를 만들어 호출할 함수를 초깃값으로 받는다.그리고 매개변수로 받은 함수를 속성으로 저장한다. 인스턴스를 다시 호출하기 위해 __call__
을 사용해준다! __call__
method에서는 함수의 시작을 알리는 문자와 끝을 알리는 문자열을 여기서는 출력해주었다.
클래스로 만든 데코레이터는 @
지정없이 데코레이터의 반환값을 호출하는 형식으로도 사용할 수 있다. 데코레이터에 호출할 함수를 넣어 인스턴스를 만들고 그 인스턴스를 호출한다! 클래스에서 이미 정의한 내용이므로 함수처럼 ()로 출력이 가능한 것이다!
def hello():
print('hello')
trace_hello = Trace(hello) # Trace 클래스에 hello 함수를 넣어 호출한다!
trace_hello
🔆 매개변수와 반환값을 처리하는 데코레이터 만들기 - class.ver
class Trace:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs): # 호출할 함수의 매개변수를 처리
r = self.func(*args, **kwargs) # self.func에 매개변수를 넣어서 호출하고 반환값을 변수에 저장
print('{0}(args={1}, kwargs={2}) -> {3}'.format(self.func.__name__, args, kwargs, r))
# 매개변수와 반환값 출력
return r # self.func의 반환값을 반환
@Trace # @데코레이터
def add(a, b):
return a + b
print(add(10, 20))
print(add(a=10, b=20))
__call__
메서드에 매개변수를 저장하고, self, func에 매개변수를 넣어서 호출한 뒤 반환값을 반환해주는 형태이다. 매개변수를 args, kwargs로 넣었으므로, self, func에 넣을 때는 언패킹해서 넣어야 한다.(args 튜플, kwargs 딕셔너리)
🙅🏻♀️ 자꾸 혼동하는 기초 개념!
[class , method, instance, object]
class Food:
def koreanfood(self):
return "맛있다!"
bulgogi = Food()
bulgogi.koreanfood()
❕ 함수를 풀어서 설명해보자면,
koreanfood 함수는 class가 할 행동을 정의하고 있다.
함수를 만든 후에는 bulgogi라는 객체를 만들었다.
bulgogi라는 객체에 .을 찍어 메서드를 불러온다!
Method : 클래스 내부에 정의된 함수 (koreanfood)
object(객체), instance(인스턴스) : bulgogi
instance : 클래스에 의해 만들어진 객체
객체와 인스턴스는 비슷한 의미이나, 인스턴스는 특정 객체가 어떤 클래스의 객체인지 관계 위주로 설명할 때 사용한다.
객체에는 정의해놓은 함수내용이 실제로 적용되며, 프로그램에서 구현할 대상이 된다.
클래스에 만들어진 객체들은 각각의 독립적인 특성을 띄고 있다.
인스턴스는 메모리에 할당되어, 실제 사용될 때 인스턴스가 된다. 인스턴스를 객체에 포함되며, 객체 지향 프로그래밍은 객체를 중심으로 프로그래밍 한다는 의미!
ex) class : 자동차의 설계도, 객체 : 만들어진 자동차.
트럭은 객체이며, 자동차의 인스턴스이다.
ex) 자주쓰고 있는 예시
user.object.get(email=data['email'])
: user의 객체의 get method를 활용해 user의 email data를 불러온다!
🟡 출처 :