중첩함수

2023. 3. 8. 10:58Python/실전 예제로 배우는 파이썬 프로그래밍

중첩함수: 함수 내부에 또 다른 함수가 내장된 형태

 

형식

def 외부함수(인수) :
	 실행문
     def 내부함수(인수) :
     	 실행문
         return 값
     return 내부함수

일급함수와 함수 클로저

파이썬의 중첩함수는 외부함수나 내부함수를 변수에 저장할 수 있는데, 이러한 특성을 갖는 함수를 일급함수(First class Function)이라고 합니다. 특히 내부함수는 외부함수의 return 명령문을 이용하여 반환하는 형태를 함수 클로저(Function cloure)라고 합니다. 함수 클로저는 외부함수가 종료되어도 내부 함수에서 선언된 변수가 메모리에서 소멸되지 않은 상태로 내부 함수를 활용할 수 있습니다.

 

실습 일급함수와 함수 클로저 예시

# (1) 일급 함수
def a():	# outer
	print('a 함수')
    
a 함수
    
    def b():	# inner
    	print('b 함수')
    return b
    
b 함수

b = a()	# 외부 함수 호출: a 함수
b()	# 내부 함수 호출: b 함수

# (2) 함수 클로저
data = list(range(1, 101))
def outer_func(data):
	dataSet = data	# 값(1~100) 생성
    # inner
    def tot():
    	tot_val = sum(dataSet)
        return tot_val
    def avg(tot_val):
    	avg_val = tot_val / len(dataSet)
        return avg_val
    return tot, avg	# inner 반환

# 외부 함수 호출: data 생성
tot, avg = outer_func(data)

# 내부 함수 호출
tot_val = tot()
print('tot =', tot_val)

tot = 5050

avg_val = avg(tot_val)
print('avg =', avg_val)

avg = 50.5

# (1) 일급함수

함수 a()를 호출하면 내부함수 b()가 반환됩니다. 이렇게 반환된 함수를 변수 b에 저장합니다. 함수를 객체로 만들어서 사용하는 것을 일급함수라고 합니다.

 

# (2) 함수 클로저

외부함수에 의해서 반환된 tot, avg 함수는 외부함수가 종료되어도 객체로 만들어지기 때문에 합계와 평균을 계산하는 데 이용할 수 있습니다.

 

중첩함수 역할

○ 외부 함수: 함수에서 사용할 자료를 만들고, 내부 함수를 포함하는 역할을 합니다.

○ 내부 함수: 외부 함수에서 만든 자료를 연산하고, 조작하는 역할을 합니다.

 

실습 산포도를 구하는 중첩함수 예시

from statistics import mean # 평균
from math import sqrt   # 제곱근

data = [4, 5, 3.5, 2.5, 6.3, 5.5]

# (1) 외부 함수: 산포도 함수
def scattering_func(data):  # outer
    dataSet = data          # data 생성
    
    # (2) 내부 함수: 산술평균 반환
    def avg_func():
        avg_val = mean(dataSet)
        return avg_val
    # (3) 내부 함수: 분산 반환
    def var_func(avg):
        diff = [(data - avg) ** 2 for data in dataSet]
        print(sum(diff))    # 차의 합
        var_val = sum(diff) / (len(dataSet) - 1)
        return var_val
    # (4) 내부 함수: 표준편차 반환
    def std_func(var):
        std_val = sqrt(var)
        return std_val   
    # 함수 클로저 반환
    return avg_func, var_func, std_func

# 내부 함수
avg, var, std = scattering_func(data)

# (5) 내부 함수 호출
print('평균: ', avg())
print('분산: ', var(avg()))
print('표준편차:', std(var(avg())))

평균:  4.466666666666667
분산:  1.9466666666666668
표준편차: 1.39522996909709

# (1) 외부 함수: 산포도 함수

외부 함수는 6개의 원소를 갖는 data 변수를 인수로 받아서 dataSet 변수에 초기화하여 산포도를 구하기 위한 자료를 생성합니다. 또한 산술평균과 분산 그리고 표준편차를 계산하는 3개의 내부 함수를 포함하고, 이들을 return으로 반환하는 역할을 합니다.

 

# (2) 내부 함수: 산술평균 반환

외부함수에서 만든 dataSet을 이용하여 산술평균을 반환하는 함수입니다.

 

# (3) 내부 함수: 분산 반환

산술평균을 인수로 받아서 dataSet의 각 변량과 차의 제곱을 계산하여 순서대로 리스트 변수인 diff에 추가합니다. 그리고 변량의 길이에서 1을 뺀 값으로 나눠서 표본의 분산을 계산하고, 반환합니다.

 

# (4) 내부 함수: 표준편차 반환

분산을 인수로 받아서 양의 제곱근을 적용하여 표준편차를 계산하고, 반환합니다.

 

# (5) 내부 함수 호출

반환된 함수 클로저를 이용하여 내부함수를 직접 호출합니다. 분산은 산술평균을 실인수로 넘겨줘야 하기에 avg()의 반환값을 var() 함수의 실인수로 넣어주고, 표준편차는 분산을 실인수로 넘겨줘야 하기에 var(avg())의 반환값을 std() 함수의 실인수로 넣어줍니다.

 

획득자, 지정자, nonlocal

○ 획득자 함수: 함수 내부에서 생성한 자료를 외부로 반환하는 함수로 반드시 return 명령문을 갖습니다.

○ 지정자 함수: 함수 내부에서 생성한 자료를 외부에서 수정하는 함수로 반드시 매개변수를 갖습니다. 만약 외부 함수에서 생성된 자료를 수정할 경우에는 해당 변수에 nonlocal 명령어를 씁니다.

 

형식

def 외부 함수() :
	변수명 = 값
   def 내부 함수() :
   	nonlocal 변수명

다음은 획득자와 지정자 함수 그리고 nonlocal 명령어를 이용하여 외부 함수에서 생성한 자료를 외부에서 획득하고, 수정하는 예문입니다.

 

실습 획득자와 지정자 예시

# (1) 중첩함수 정의
def main_func(num):
	num_val = num	# 자료 생성
    def getter():	# 획득자 함수, return 있음
    	return num_val
    def setter(value):	# 지정자 함수 인수 있음
    	nonlocal num_val	# nonlocal 명령어
        num_val = value
     
    return getter, setter	# 함수 클로저 반환
    
# (2) 외부 함수 호출
getter, setter = main_func(100)	# num 생성

# (3) 획득자 호출
print('num =', getter())	# 획득한 num 확인

num = 100

# (4) 지정자 획득
setter(200)	# num 값 수정
print('num =', getter())	# num 수정 확인

num = 200

# (1) 중첩함수 정의

외부 함수에서 num을 인수로 받아서 num_valu 변수에 할당하여 자료를 만듭니다. 또한 획득자와 지정자 함수를 포함하고, 이들을 return으로 반환하는 역할을 합니다.

 

# (2) 외부 함수 호출

실인수 100을 넘겨서 중첩함수를 호출하면 num_val 변수에 100이 할당되고, 두 개의 함수 클로저를 반환합니다.

 

# (3) 획득자 호출

함수 클로저 getter를 이용하여 획득자 함수를 호출하면 num_val의 값이 반환됩니다.

 

# (4) 지정자 획득

함수 클로저 setter를 이용하여 실인수 200으로 지정자 함수를 호출하면 외부 함수에서 만들어진 num_val의 값이 200으로 수정됩니다.

 

함수 장식자

함수 장식자(decoration): 기존 함수의 시작 부분과 종료 부분에 기능을 장식해서 추가해 주는 별도의 함수로 현재 실행되는 함수를 파라미터로 받아서 꾸며줄 내용과 함께 해당 함수를 감싸주는 함수(wrapping function)입니다.

 

형식

@함수 장식자
def 함수명():
	실행문

실습 함수 장식자 예시

# (1) 래퍼 함수
def wrap(func):
    def decorated():
        print('방가워요!')  # 시작 부분에 삽입
        func()  # 인수로 넘어온 함수(hello)
        print('잘가요!')    # 종료 부분에 삽입
    return decorated    # 클로저 함수 반환

# (2) 함수 장식자 적용
@wrap
def hello():
    print('hi ~ ', "홍길동")

# (3) 함수 호출
hello()

방가워요!
hi ~  홍길동
잘가요!

# (1) 래퍼 함수

(func)는 현재 실행되는 함수(hello)를 인수로 받는 매개변수이고, decorated() 내부 함수는 인수로 받는 함수의 시작 부분과 종료 부분에 삽입할 명령문을 작성하고 있습니다.

 

# (2) 함수 장식자 적용

hello() 함수를 대상으로 래퍼 함수를 적용하기 위해서 함수 장식자(@wrap)를 함수 앞부분에 붙입니다.

 

# (3) 함수 호출

함수 장식자가 적용된 hello() 함수를 호출하면 함수 장식자가 호출되면서 hello() 함수 실행문('hi ~ 홍길동')을 중심으로 시작 부분에 '방가워요!', 종료 부분에 '잘 가요!'가 각각 장식으로 추가됩니다.

'Python > 실전 예제로 배우는 파이썬 프로그래밍' 카테고리의 다른 글

프로그램 블록 만들기 연습문제  (0) 2023.03.10
재귀함수(Recursive function)  (0) 2023.03.09
특수함수  (0) 2023.03.07
사용자정의함수  (0) 2023.03.06
내장함수  (0) 2023.03.05