Nested Function
중첩함수
- 함수 내에 정의된 함수
- 중첩함수는 상위 함수 내에서 호출 및 반환 가능
- 중첩함수는 상위 함수 외부에서 호출 불가
- 중첩함수를 사용하면 가독성을 높일 수 있음
예시 1 ) 중첩함수는 상위 함수 내에서 호출 및 반환 가능
def outer_func():
print ('외부함수')
# 중첩 함수
def inner_func():
return '중첩함수'
print (inner_func())
# 함수에서 중첩함수 호출 가능
outer_func()
# 외부함수
# 중첩함수
예시 2 ) 중첩함수는 상위 함수 외부에서 호출 불가
def outer() :
x=100
def inner():
x=1000
return x
return x
print (outer()) # 100
print (inner())
# NameError: name 'inner' is not defined
# 상위 함수(외부 함수) 밖에서 호출 불가능
First Class Object
객체 (object)
- 메모리에 존재하는 데이터를 가리키는 개념
- 파이썬의 모든 데이터는 객체나 객체 간의 관계로 표현됨
- 숫자, 문자열, 튜플 등
First Class Object
다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체
보통 아래의 연산을 지원할 때 일급 객체라고 함
- 변수(variable)에 담을 수 있음
- 매개변수(parameter)로 전달 할 수 있음
- 반환 값(return value)이 될 수 있음
파이썬에서 함수는 일급 객체
예시 1 ) 함수를 변수에 할당 가능
def yell(text):
return text.upper()
# 함수를 변수에 할당
bark = yell
print (yell('python'))
# PYTHON
print (bark('python'))
# PYTHON
예시 2 ) 함수를 매개변수(parameter)로 전달 가능
def yaho(func) :
return func('yaho!')
# 함수 yell을 매개변수로 전달
print (yaho(yell))
# YAHO!
예시 3 ) 함수가 return value가 될 수 있음
def add(a,b) :
return a+b
# 함수를 return value로 사용할 수 있음
def cal(*args):
return add(*args)-3
print (cal(4,3))
# 4
위의 예시들을 통하여 파이썬에서 함수는 1급 객체라는 것을 확인할 수 있음
이러한 1급 객체의 특성이 있어야 closure가 성립
nonlocal
outer 함수의 안에 있으며 inner 함수의 밖에 있는 영역
자세한 내용은 여기를 참조
Closure
- 중첩 함수가 상위 함수의 변수/ 정보를 가두어 사용하는 것
- 내부 함수(중첩 함수)가 외부 함수(상위 함수)의 맥락에 접근할 수 있는 것
closure의 조건
- 중첩 함수여야 함
- 외부 함수 내의 값을 반드시 참조해야 함
- 외부 함수는 중첩 함수를 return해야 함
closure 예시
아래는 closure의 예시
def root_cal(number) :
def nth_root(rt):
return number**(1/rt)
return nth_root
아래의 그림과 같은 구조로 이루어져 있음
이 함수를 이용하여 계산을 진행하면 다음과 같이 진행됨
def root_cal(number) :
def nth_root(rt):
return number**(1/rt)
return nth_root
find_1000_nth_root=root_cal(1000)
print (find_1000_nth_root(2))
# 31.622776601683793
print (find_1000_nth_root(3))
# 9.999999999999998
진행 순서를 도식화 하면 다음과 같음
3 --> 4 번 순서를 지나며
root_cal(1000)의 결과가 nth_root(rt)를 return한다는 것을 저장
5번 순서를 지나며 find_1000_nth_root가 nth_root(rt)값을 받아옴을 저장
6번 순서를 지나며 rt=3
따라서 31.6228이라는 값을 return함
아래의 이미지로 위의 내용을 정리할 수 있음
closure의 장점
-
global 변수를 사용하지 않아도 됨 (nonlocal 변수를 사용하기 때문에)
- 따라서 변수의 불필요한 충돌을 방지 할 수 있음
-
데이터를 숨기기 용이함
- closure에 속한 지역 변수는 바깥에서 직접 접근할 수 없음
- 클로저는 외부 함수의 상태값을 참조, 함수가 메모리에서 사라져도 값이 유지됨 (아래의 예시 참조)
예시 )
def root_cal(number) :
def nth_root(rt):
return number**(1/rt)
return nth_root
find_1000_nth_root=root_cal(1000)
del(root_cal)
# root_cal 함수를 삭제
print (find_1000_nth_root(4))
# 5.623413251903491
위와 같이 root_cal( ) 함수를 삭제하였음에도 해당 함수를 find_1000_nth_root 함수는 사용할 수 있음
- decorator를 시행할 수 있음
Decorator
- 다른 함수를 인자로 받아서 그 함수를 꾸며주는 함수
- 외부함수가 내부함수를 return 함
- 다른 함수를 decorator 함수의 인자로 전달
decorator의 구조
def decorator_func(other_func):
def wrapper_func():
other_func() # 다른 함수를 인자로 받음
print ('그 외 other_func를 꾸며줄 내용')
return wrapper_func # 외부함수가 내부함수를 return
decorator의 이용_1
아래의 예시와 같이 decorator를 이용할 수 있음
예시)
def decorator_func(other_func):
def wrapper_func():
other_func() # 다른 함수를 인자로 받음
print ('그 외 other_func를 꾸며줄 내용')
return wrapper_func # 외부함수가 내부함수를 return
def 적용할_함수() :
print ('이 함수를 인자로 받음')
imple=decorator_func(적용할_함수)
imple()
# 이 함수를 인자로 받음
# 그 외 other_func를 꾸며줄 내용
decorator의 이용_2
@를 이용하여 decorator를 간단하게 나타낼 수 있음
def decorator_func(other_func):
def wrapper_func():
other_func()
print ('그 외 other_func를 꾸며줄 내용')
return wrapper_func
@ decorator_func
def 적용할_함수():
print ('이 함수를 인자로 받음')
# 위의 imple=decorator_func(적용할_함수)와 동일한 의미
적용할_함수()
# 이 함수를 인자로 받음
# 그 외 other_func를 꾸며줄 내용
하나의 함수에 여러개의 decorator를 적용할 수 있음
아래의 예시처럼 사용할 수 있음
예시)
def decorator1(func) :
def wrapper1(*args) :
print('Hello')
func(*args)
return wrapper1
def decorator2(func):
def wrapper2(*args) :
func(*args)
print ('Nice to meet you')
return wrapper2
@decorator1
@decorator2
def other_func(name):
print (f'{name}')
other_func('Jina')
# Hello
# Jina
# Nice to meet you
만약에 name으로 여러개의 값을 받고 싶다면
def decorator1(func) :
def wrapper1(*args) :
print('Hello')
func(*args)
return wrapper1
def decorator2(func):
def wrapper2(*args) :
func(*args)
print ('Nice to meet you')
return wrapper2
@decorator1
@decorator2
def other_func(*name):
print (f'{name}')
other_func('Jina','Naji')
#Hello
#('Jina', 'Naji')
#Nice to meet you
def other_func(*name) : 여기에도 args를 받는다는 표현을 해주어야함!
parameter를 가지는 decorator
decorator에 parameter를 전달하고 싶을 때는
function을 감싸는 decorator를 또 감싸주고 parameter를 전달해주면 됨
아래의 예시를 참고하기
def parameter_decorator(para):
def function_decorator(func):
def wrapper(*args):
print (para)
func(*args)
return wrapper
return function_decorator
@parameter_decorator("Parameter")
def func(args):
print (f"function {args}")
func("decorator")
# Parameter
#function decorator
위의 사진을 보면 파란색으로 표시된 영역 A가 Decorator
이 데코레이터는 function을 조작하는 역할을 함
파란색 영역을 감싸고 있는 B는 A(decorator)를 중첩함수로 받아서 function에 parameter를 전달해줌
Ref
아래의 내용을 참고 및 정리
https://tech.ssut.me/python-functions-are-first-class/
https://shoark7.github.io/programming/python/closure-in-python _
_https://jiminsun.github.io/2018-05-07/python-closure/
https://data-flair.training/blogs/python-closure/
https://nachwon.github.io/decorator/
http://abh0518.net/tok/?p=604
'python > Today I Learned' 카테고리의 다른 글
Modules & Packages_1 (0) | 2020.04.04 |
---|---|
Class (2) | 2020.03.31 |
Scope (1) | 2020.03.30 |
Set (1) | 2020.03.26 |
CSS (0) | 2020.03.24 |
댓글