728x90
반응형
<클로저(Closure)>
- 함수 안에 함수를 만들어서 사용하는 방식
- 함수 안에 있는 함수는 바깥족 함수에서 참조해서 사용하는 방식으로 접근합니다.
- 함수 안에 함수는 사용이 끝나면 메모리에서 해제되기 때문에 유용하게 사용하면 좋습니다.
- 프로그래밍 언어에서 함수가 자신을 포함하는 범위(scope) 외부의 변수에 접근할 수 있는 기능. 클로저를 사용하면 함수가 정의된 위치에 따라 변수에 접근할 수 있어, 함수를 반환하거나 다른 함수에 전달할 때 해당 함수의 환경을 유지할 수 있다.
#클로저 함수 기초
## 클로저 함수 정의하기
def outer_function(x):
print(f"#1 : x = {x}")
###내부 함수 정의 : 실제 실행되는 함수
def inner_function(y):
print(f"#2 : y = {y}")
s = x+ y
print(f"#3 ; s = {s}")
return s
print("#4--------")
return inner_function
### 클로저 함수 호출하기
closure_exe = outer_function(10)
print(closure_exe)
#- closure_exe는 inner_function 자체를 리턴 받은 함수를 의미함
#1 : x = 10
#4--------
<function outer_function.<locals>.inner_function at 0x0000025941815A80>
###내부 클래스 호출
closure_exe(5)
#2 : y = 5
#3 ; s = 15
15
### 클로저를 이용해서 누적합 계산하기
# - 사용함수 명 : outer_function2(), inner_function2(num)
# - 사용변수 : total (누적된 값을 저장할 변수)
def outer_function2():
total = 0
print( f"#1 : total = {total}")
def inner_function2(y):
#nonlocal : 클로저 구조에서는 상위 변수를 내부 함수에서 사용못함
# 따라서 , nonlocal을 지정해서 정의하고 외부 영역의 변수 사용가능
nonlocal total
print(f'#2 : total = {total} / num = {y}')
total+=y
print(f'#3 : total = {total} / num = {y}')
return total
print(f'#4 : total = {total}' )
return inner_function2
a = outer_function2()
a
#1 : total = 0
#4 : total = 0
<function __main__.outer_function2.<locals>.inner_function2(y)>
##내부 함수 호출
a(4)
#2 : total = 4 / num = 4
#3 : total = 8 / num = 4
8
<조건부 클로저 함수 프로그래밍>
def outer_function3(condition):
def true_case():
return "true_case 함수가 호출되었습니다"
def false_case():
return "false_case 함수가 호출되었습니다"
##condition 의 값이 True면 true_case 함수 정의 False이면 false_case 함수 정의
rs = true_case if condition else false_case
return rs
### 상위 함수 호출하기
rs_fuction= outer_function3(True)
print(rs_fuction)
rs_fuction= outer_function3(False)
print(rs_fuction)
<function outer_function3.<locals>.true_case at 0x00000259430CFE20>
<function outer_function3.<locals>.false_case at 0x00000259430CFCE0>
rs_msg=rs_fuction()
print(rs_msg)
false_case 함수가 호출되었습니다
< 데코레이터(Decorator)>
- 함수의 재사용성을 활장한 개념의 방법
<함수 실행 시간 확인하는 데토레이터 프로그램 작성> - 함수나 메소드의 동작을 수정하거나 확장하기 위한 특별한 기능을 제공하는 것.
- 데코레이터는 함수를 취하여 해당 함수의 동작을 변경하고, 주로 코드 재사용성과 모듈성을 높이는 데에 사용된다. 파이썬에서는 @decorator 문법을 통해 사용할 수 있다.
import time
### 데코레이터 함수정의하기
# -func : 실제 처리할 함수 받아오는 매개변수
def timer_decorator(func):
print(f'#1 : func = {func}')
### 실제 실행될 함수 정의: (함수 이름은 자유롭게)
# - func로 받은 함수를 아래 함수로 재정의하게 됨
def wrapper(*args, **kwargs): ### *하나는 매개변수 **두개는 딕셔너리
# - 시작시간
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_functuion이 됩니다.
@timer_decorator
def exe_function():
print("실제 처리할 함수")
### 2초간 대기 : 데코레이터가 처리되는 시간을 벌어주기 위해서
time.sleep(2)
#1 : func = <function exe_function at 0x0000022CE5BC7880>
#5==============
### 실제 처리 하기
exe_funtion()
#2 : start_time = 1699932725.0213323
실제 처리할 함수
#3 : rs = None
#4 : end_time = 1699932727.033138
<로그 데코레이터>
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 rs
print('#2-------------')
return wrapper
### 데코레이터 호출 및 처리함수 정의
@log_decorator
def another_function():
print("여긴 어디 나는 누구?")
#1 :func = <function another_function at 0x0000022CE6ED6D40>
#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 :
args1 = ["인증성공" , "안녕"]
print (f' #4 : args = {args1}')
return func(*args1, **kwargs)
else:
print (' #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 0x0000022CE62B60C0>
#6-----------
### 처리할 함수 호출
admin_function()
#3 : check_id = admin
#4 : args = ['인증성공', '안녕']
인증 결과 : ('인증성공', '안녕')
### 함수 이름 자유롭게 생성
# 데코레이터 함수 생성하셔서 대문자로 출력까지
def decorator_upper(func):
### 인자로 넘어온 2개의 소문자는 args 매개변수가 받게됨
def wrapper(*args, **kwargs):
### 인자로 넘겨받은 개의 소문자를 대문자로 처리하는 영역
args= [arg.upper() for arg in args]
### 대문자로 변환된 값 2개를 args에 리스트 타입으로 담아서 넘기면 됨
return func(*args, **kwargs)
return wrapper
### 데코레이터 호출 및 처리 함수 정의
@decorator_upper
def getUpper(param1, param2):
print(f' 대문자 변환 결과 : {param1}/ {param2}')
### 처리하는 함수 호출 : 소문자 2개를 인자로 넘겨주기
getUpper("hellow", "world")
대문자 변환 결과 : HELLOW/ WORLD
### 가변 키워드 매개변수를 사용한 함수
# 전달할 값이이 몇개 일지 모를때 사용하는 방식
# 행은 리스트 열은 딕셔너리
def function4(**args):
print(args)
function4 (a=1, b=2 ,c= 3)
dic = {"a": 33, "b":55}
function4(**dic)
{'a': 1, 'b': 2, 'c': 3}
{'a': 33, 'b': 55}
도서 관리 프로그램을 데코레이터를 사용하여 수정할 수 있다.
# 기능을 수행할 클래스 (모듈 or 라이브러리)생성
class LibraryKiosk:
### 클래스 생성자 정의
def __init__(self):
### 도서 목록을 저장할 딕셔너리 변수 생성
# - 도서 번호, 도서 제목, 도서 재고 수량 정보 담기
self.books = {}
print("클래스가 생성되었습니다")
#------------------------------------------------------------------
def book_decorator(func):
def wrapper(self, *args):
## 입고할 도서번호가 존재하는 지 확인
## 존재한다면 수량만 증가시키기
func(self,*args)
return wrapper
#클로저 개념 와퍼는 사라질 것이기 때문에 대용량 데이터를 다룰 때 메모리 쪼금
#------------------------------------------------------------------
@book_decorator
def add_book(self, book_id, title, quantity):
## 입고할 도서번호가 존재하는 지 확인
## 존재한다면 수량만 증가시키기
if book_id in self.books:
# self.books[book_id][quantity] = self.books[book_id][quantity] + quantity
self.books[book_id]["quantity"] += quantity
else: ##존재하지 않는다면
#{ 001 : {'title': 파이썬기초, "quantity:5}}
self.books[book_id] ={ "title": title, "quantity": quantity}
print (f"도서번호 :{book_id} / 제목 / : {title} / 입고수량 : {quantity} / 입고확인")
print(self.books)
@book_decorator
def borrow_book(self, book_id):
# 대출하고자하는 해당하는 재고 수량확인하기
if (book_id in self.books) and (self.books[book_id]["quantity"]>0) :
# ["quantity"] = self.books[book_id]["quantity"]-1
self.books[book_id]["quantity"]-=1
print(f"제목: {self.books[book_id]['title']} / 남은 재고 수량: {self.books[book_id]['quantity']}")
#해당 도서가 없거나 재고가 없다면
else:
print("도서가 존재하지 않거나 , 대출할 재고가 없습니다.")
@book_decorator
def return_book(self, book_id):
# 빈닙히고자하는 해당하는 재고 수량확인하기
if (book_id in self.books):
self.books[book_id]["quantity"]+=1
print(f"제목: {self.books[book_id]['title']} / 남은 재고 수량: {self.books[book_id]['quantity']}")
# 해당 도서가 없다면
else:
print("해당 도서가 존재하지 않습니다.")728x90
반응형
'파이썬' 카테고리의 다른 글
| 메모리 절약을 위한 제너레이터 사용 (0) | 2023.11.16 |
|---|---|
| 메모리 절약 - 이터레이터 (1) | 2023.11.16 |
| 유니코드 짧은 (2) | 2023.11.14 |
| 도서 입고/대출반납 관리를 위한 키오스크 파이썬 프로그램 실습 (4) | 2023.11.13 |
| 파이썬 class 클래스 (1) | 2023.11.10 |