<데코레이터(Decorator)>
함수의 재사용성을 확장한 개념의 방법
<함수 실행 시간 확인하는 데코레이터 프로그램 작성>
### 데코레이터 함수 정의하기
# = func : 실제 처리할 함수 받아오는 매개변수
def timer_decorator(func) :
print(f"#1 : func = {func}")
### 실제 실행될 함수 정의 (함수 이름은 자유롭게)
# - func로 받은 함수를 아래 함수로 재정의하게 됨
def wrapper(*args, **kwargs) :
# - tlwkrtlrks
start_time = time.time()
print(f"#2 : start_time = {start_time}")
### 실제 처리할 함수 : func
rs = func(*args, **kwargs)
print(f"#3 : rs = {rs}")
#- 정료시간
end_time = time.time()
print(f"#4 : end_time = {end_time}")
return rs
print("#5 ------------------")
return wrapper
### 데코레이터 호출 및 처리할 함수 정의하기
# - 데코레이터 호출은 @를 사용함
# = 데코레이터 함수 호출 시 밑에 정의된 함수(exe_function)가 자동으로 전달됨
# - 데코레이터 함수가 리턴한 wrapper 함수는 exe_function 가 된다.
# (재정의 되는 시점)
@timer_decorator
def exe_function() :
print("실제 처리할 함수")
### 2초간 대기 : 데코레이터가 처리되는 시간을 벌어주기 위해서
time.sleep(2)
#1 : func = <function exe_function at 0x0000022A81F058A0>
#5 ------------------
### 실제 처리하기
exe_function()
#2 : start_time = 1699930617.996027
실제 처리할 함수
#3 : rs = None
#4 : end_time = 1699930619.9973152
def log_decorator(func) :
print(f"#1 : func = {func}")
def wrapper(*args, **kwargs) :
print(f"Logo : {func.__name__} 함수 호출됨")
rs = func(*args, **kwargs)
print(f"Logo : {func.__name__} 함수 호출됨")
return
print("#2 ----------")
return wrapper
### 데코레이터 호출 및 처리함수 정의
@log_decorator
def another_function() :
print("여긴 어디? 넌 누구?")
#1 : func = <function another_function at 0x0000022A82005580>
#2 ----------
### 처리함수 호출
another_function()
Logo : another_function 함수 호출됨
여긴 어디? 넌 누구?
Logo : another_function 함수 호출됨
<데코레이터 내부함수에섳 처리된 결과를 받아보기>
def check_permission(param_id) :
print(f"#1 : param_id = {param_id}")
def decorator(func) :
print(f"#2 : func = {func}")
def wrapper(*args, **kwargs) :
check_id = "admin"
print(f"#3 : check_id = {check_id}")
if check_id == param_id :
args = ["인증성공"]
print(f"#4 : args = {args}")
return func(*args, **kwargs)
else :
print(f"#5 : raise명령으로 강제 오류 발생 ")
raise permissionError("접근 불기!!")
print("#6 ------------")
return wrapper
print("#7 ------------")
return decorator
### 데코레이터 호출 및 처리함수 정의
@check_permission(param_id = "admin")
def admin_function(rs_msg) :
print(f"인증 결과 : {rs_msg}")
#1 : param_id = admin
#7 ------------
#2 : func = <function admin_function at 0x0000022A8267C5E0>
#6 ------------
### 처리함수 호출
admin_function()
#3 : check_id = admin
#4 : args = ['인증성공']
인증 결과 : 인증성공
<영문 소문자 2개를 매개변수로 받아서, 대문자로 변환하는 데코레이터 프로그램>
### 함수이름 자유롭게..생성
# = 데코레이터 함수 생성하셔서 대문자로 출력까지...
def decorator_upper(func) :
### 인자로 넘어온 2개의 소문자는 args 매개변수가 받게됨
def warpper(*args, **kwargs) :
### 인자로 넘겨받은 개의 소문자를 대문자로 처리하는 영역
args = [arg.upper() for arg in args]
### 대문자로 변횐된 값 2개를 args에 리스트 타입으로 담아서 넘기면 됨
return func(*args, **kwargs)
return warpper
### 데코리이터 호출 및 처리 함수 정의
@decorator_upper
def getUpper(param1, param2) :
print(f"대문자로 변환된 {param1} / {param2}")
### 처리하는 함수 호출 : 소문자 2개를 인자로 넘겨주기
getUpper("abcd", "efgh")
대문자로 변환된 ABCD / EFGH
1 2
### 기본값(default) 정의 매개변수를 사용하는 함수
def function2(a, b=3) :
print(a, b)
function2(4)
4 3
### 키워드 정의 방식
def function3(a, b) :
print(a, b)
function3(a=3, b=5)
function3(b=6, a=4)
3 5
4 6
### 가변형 매개변수를 사용한 함수
# 전달할 값이 몇개 일지 모를때 사용하는 방식
def function4(*args) :
print(args)
function4(1,2,3,5)
function4(1,2,3,6,9)
(1, 2, 3, 5)
(1, 2, 3, 6, 9)
### 가변 키워드 매개변수를 사용한 함수
# 전달할 값이 몇개 일지 모를때 사용하는 방식
def function5(**args) :
print(args)
function5(a=1,b=2,c=3)
function5(a=1,b=2,c=3,d=6,e=9)
dic = {"a" : 33, "b" : 55}
function5(a =33, b = 55)
function5(**dic)
{'a': 1, 'b': 2, 'c': 3}
{'a': 1, 'b': 2, 'c': 3, 'd': 6, 'e': 9}
{'a': 33, 'b': 55}
{'a': 33, 'b': 55}
<실습> 어제 작성한 도서관리 프로그램을 데코레이터를 적용하기>
class LibraryKiosk :
def __init__(self) :
self.books = {}
print("클래스 생성 되었습니다.")
# ------------------------------------------------------------------------
###도서입고 데코레이터 함수 정의하기
def add_book_decorator(func) :
def wrapper(self, book_id, title, quantity) :
func(self, book_id, title, quantity)
return wrapper
def borrow_book_decorator(func) :
def wrapper(self, book_id) :
func(self, book_id)
return wrapper
def return_book_decorator(func) :
def wrapper(self, book_id) :
func(self, book_id)
return wrapper
# ------------------------------------------------------------------------
@add_book_decorator
def add_book(self, book_id, title, quantity) :
if book_id in self.books :
self.books[book_id]["quantity"] += quantity
else :
self.books[book_id] = {"title" : title, "quantity" : quantity}
print(f"도서번호 : {book_id} / 제목 : {title} / 입고수량 : {quantity} 입고 성공")
def borrow_book(self, book_id) :
if (book_id in self.books) and (self.books[book_id]["quantity"] > 0) :
self.books[book_id]["quantity"] -= 1
print(f"도서번호 : {book_id} / 제목 : {self.books[book_id]['title']} / 남은재고수량 : {self.books[book_id]['quantity']}")
else:
print("도서가 존재하지 않거나, 대출할 재고가 없습니다.")
def return_book(self, book_id) :
if book_id in self.books :
self.books[book_id]["quantity"] += 1
print(f"도서번호 : {book_id} / 제목 : {self.books[book_id]['title']} / 남은재고수량 : {self.books[book_id]['quantity']}")
else:
print("해당 도서가 존재하지 않습니다. ")
def main() :
kiosk = LibraryKiosk()
print(kiosk)
while True:
print("<도서 키오스크 메뉴>")
print("1. 도서입고")
print("2. 도서대출")
print("3. 도서반납")
print("4. 종료")
choice = input("원하는 번호(1~4)를 선택하세요 : ")
if choice == "1":
book_id = input("도서 번호를 입력해 주세요: ")
title = input("도서 제목를 입력해 주세요: ")
quantity= int(input("입고할 권수를 입력해 주세요: "))
print(f"{book_id}/{title}/{quantity}")
kiosk.add_book(book_id, title, quantity)
elif choice == "2":
print("대출 선택")
book_id = input("대출할 도서번호를 입력해주세요 : ")
kiosk.borrow_book(book_id)
elif choice == "3":
print("반납 선택")
book_id = input("반납할 도서번호를 입력해주세요 : ")
kiosk.return_book(book_id)
elif choice == "4":
print("종료 선택")
break
else:
print("번호를 확인해주세요")
if __name__ == '__main__' :
main()