[파이썬] 재귀 함수, 합성 함수

재귀 함수: 자기 자신의 함수를 함수 내 연속적으로 호출하여 처리하는 함수
합성 함수: 다른 함수를 매개 변수로 받거나 반환하여 처리하는 함수
 

I. 재귀 함수

  • 재귀 함수 사용 시 별도의 순환문을 사용하지 않아도 반복 처리 효과
  • 파이썬에서는 재귀 함수를 무한정 사용할 수 없도록 제한
  • [예제] 함수 재귀 호출
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import timeit
def func1(list1) :
if len(list1) == 1 : # 마지막 처리 로직으로 무한 수행 방지
return list1[0]
head, *tail = list1 # 처리값 감소 위해 첫 번째 원소는 head, 나머지 원소는 tail에 삽입
return head + func1(tail) # tail을 인자로 전달해서 자신을 호출
time1 = timeit.timeit('func1([1,2,3])', setup = "from __main__ import func1", number = 1000000)
print("재귀함수 처리 시간:", time1)
def func2(list2) : # 재귀 함수 처리 시간과 비교하기 위해 순환문 사용
result = 0
for i in list2 :
result += i
return result
time2 = timeit.timeit('func2([1,2,3])', setup = "from __main__ import func2", number = 1000000)
print("순환문 처리 시간:", time2)
[결과]
귀함수 처리 시간: 0.8320854999999999
순환문 처리 시간: 0.26898349999999993
import timeit def func1(list1) : if len(list1) == 1 : # 마지막 처리 로직으로 무한 수행 방지 return list1[0] head, *tail = list1 # 처리값 감소 위해 첫 번째 원소는 head, 나머지 원소는 tail에 삽입 return head + func1(tail) # tail을 인자로 전달해서 자신을 호출 time1 = timeit.timeit('func1([1,2,3])', setup = "from __main__ import func1", number = 1000000) print("재귀함수 처리 시간:", time1) def func2(list2) : # 재귀 함수 처리 시간과 비교하기 위해 순환문 사용 result = 0 for i in list2 : result += i return result time2 = timeit.timeit('func2([1,2,3])', setup = "from __main__ import func2", number = 1000000) print("순환문 처리 시간:", time2) [결과] 귀함수 처리 시간: 0.8320854999999999 순환문 처리 시간: 0.26898349999999993
import timeit

def func1(list1) :
    if len(list1) == 1 :        # 마지막 처리 로직으로 무한 수행 방지
        return list1[0]
    head, *tail = list1         # 처리값 감소 위해 첫 번째 원소는 head, 나머지 원소는 tail에 삽입
    return head + func1(tail)   # tail을 인자로 전달해서 자신을 호출

time1 = timeit.timeit('func1([1,2,3])', setup = "from __main__ import func1", number = 1000000)
print("재귀함수 처리 시간:", time1)

def func2(list2) :              # 재귀 함수 처리 시간과 비교하기 위해 순환문 사용
    result = 0
    for i in list2 :
        result += i
    return result

time2 = timeit.timeit('func2([1,2,3])', setup = "from __main__ import func2", number = 1000000)
print("순환문   처리 시간:", time2)

[결과]
귀함수 처리 시간: 0.8320854999999999
순환문   처리 시간: 0.26898349999999993
  • 재귀함수와 순환문 처리 성능 비교 시 재귀 함수 호출 시 함수를 계속적으로 생성하여 처리해야 하므로 순환문 처리 성능이 높음

 

II. 합성 함수

  • 함수도 객체이므로 다른 객체처럼 인자로 전달하여 사용 가능
  • [예제] 합성 함수 처리
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import math
def add(a, b) : # 인자로 전달할 함수 정의
return a + b
def power(func, *args, z=None) : # 전달받는 함수와 인자를 매개변수로 정의
result = func(*args) # 인자를 전달 받아 수행
if z :
result = math.pow(result, z) # 키워드 인자가 들어오면 합한 값을 제곱
return result
print(power(add, 1, 3, z = 2))
[결과]
16.0
import math def add(a, b) : # 인자로 전달할 함수 정의 return a + b def power(func, *args, z=None) : # 전달받는 함수와 인자를 매개변수로 정의 result = func(*args) # 인자를 전달 받아 수행 if z : result = math.pow(result, z) # 키워드 인자가 들어오면 합한 값을 제곱 return result print(power(add, 1, 3, z = 2)) [결과] 16.0
import math

def add(a, b) :     # 인자로 전달할 함수 정의
    return a + b

def power(func, *args, z=None) :    # 전달받는 함수와 인자를 매개변수로 정의
    result = func(*args)            # 인자를 전달 받아 수행
    if z :
        result = math.pow(result, z)    # 키워드 인자가 들어오면 합한 값을 제곱
    return result

print(power(add, 1, 3, z = 2))

[결과]
16.0

 

III. 재귀 함수 실행 시 객체 이름공간 사용

  • 함수도 객체이므로 함수 자체 이름공간과 함수 내부 지역 이름공간이 생성
  • 함수 정의 시 생성된 이름공간은 함수 실행 시 공유하여 사용 가능
  • [예제] 순환문 없이 순환 수행
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def recursion(iterable) : # 하나의 매개변수를 가지는 재귀 함수
if not isinstance(iterable, list) : # 매개변수 자료형이 리스트 클래스가 아니면 종료
return "처리 불가"
if not hasattr(recursion, "result") : # 함수 객체에 속성이 없으면 빈 리스트 할당
recursion.result = []
if len(iterable) == 1 : # 반복 원소의 길이가 1이면
recursion.result.append(iterable.pop()) # 마지막 원소를 함수 객체의 속성에 추가 후 종료
return None
recursion.result.append(iterable.pop(0)) # 원소를 하나씩 객체 속성에 추가
return recursion(iterable) # 자기 함수 호출
recursion([1,2,3])
print(recursion.result)
print(recursion("문자열 처리"))
[결과]
[1, 2, 3]
처리 불가
def recursion(iterable) : # 하나의 매개변수를 가지는 재귀 함수 if not isinstance(iterable, list) : # 매개변수 자료형이 리스트 클래스가 아니면 종료 return "처리 불가" if not hasattr(recursion, "result") : # 함수 객체에 속성이 없으면 빈 리스트 할당 recursion.result = [] if len(iterable) == 1 : # 반복 원소의 길이가 1이면 recursion.result.append(iterable.pop()) # 마지막 원소를 함수 객체의 속성에 추가 후 종료 return None recursion.result.append(iterable.pop(0)) # 원소를 하나씩 객체 속성에 추가 return recursion(iterable) # 자기 함수 호출 recursion([1,2,3]) print(recursion.result) print(recursion("문자열 처리")) [결과] [1, 2, 3] 처리 불가
def recursion(iterable) :                       # 하나의 매개변수를 가지는 재귀 함수
    if not isinstance(iterable, list) :         # 매개변수 자료형이 리스트 클래스가 아니면 종료
        return "처리 불가"
    if not hasattr(recursion, "result") :       # 함수 객체에 속성이 없으면 빈 리스트 할당
        recursion.result = []
    if len(iterable) == 1 :                     # 반복 원소의 길이가 1이면 
        recursion.result.append(iterable.pop()) # 마지막 원소를 함수 객체의 속성에 추가 후 종료
        return None
    
    recursion.result.append(iterable.pop(0))    # 원소를 하나씩 객체 속성에 추가
    return recursion(iterable)                  # 자기 함수 호출

recursion([1,2,3])
print(recursion.result)

print(recursion("문자열 처리"))

[결과]
[1, 2, 3]
처리 불가

 

[참고]

  • 잇플, “한 권으로 개발자가 원하던 파이썬 심화 A to Z”, 2019.11

콘텐츠 사용 시 출처 표기 부탁 드리고, 댓글은 큰 힘이 됩니다^^