클로저와 데코레이터는 파이썬에서 중요한 개념으로, 함수와 클래스의 활용도를 높여주는 기능이다.
클로저는 함수 내부에 또 다른 함수를 정의하고, 이 내부 함수를 반환하는 구조를 말한다. 클로저를 사용하면 외부 함수의 변수를 내부 함수에서 기억하고 사용할 수 있다.
def mul3(n):
return n * 3
def mul5(n):
return n * 5
위 코드에서는 mul3, mul5처럼 특정 값을 곱하는 함수들을 각각 정의하고 있다. 하지만 비슷한 함수들을 계속 만드는 것은 비효율적이다.
class Mul:
def __init__(self, m):
self.m = m
def __call__(self, n):
return self.m * n
mul3 = Mul(3)
mul5 = Mul(5)
print(mul3(10)) # 30 출력
print(mul5(10)) # 50 출력
클래스를 사용하면 특정 값을 미리 설정해 두고, 객체를 통해 그 값을 곱하는 메서드를 사용할 수 있다.
def mul(m):
def wrapper(n):
return m * n
return wrapper
mul3 = mul(3)
mul5 = mul(5)
print(mul3(10)) # 30 출력
print(mul5(10)) # 50 출력
클로저를 사용하면 내부 함수 wrapper가 외부 함수의 인자 m을 기억해, 클래스 없이도 비슷한 기능을 구현할 수 있다.
데코레이터는 기존 함수에 새로운 기능을 추가할 수 있는 방법이다. 이를 통해 기존 코드를 수정하지 않고도 기능을 확장할 수 있다.
import time
def elapsed(original_func):
def wrapper(*args, **kwargs):
start = time.time()
result = original_func(*args, **kwargs)
end = time.time()
print("함수 수행시간: %f 초" % (end - start))
return result
return wrapper
@elapsed
def myfunc(msg):
print("'%s'을 출력합니다." % msg)
myfunc("You need python")
위 코드에서 elapsed 데코레이터는 함수의 실행 시간을 측정해준다. @elapsed를 사용해 myfunc 함수에 이 데코레이터를 적용하면, myfunc가 실행될 때마다 자동으로 수행 시간이 출력된다.
import time
def elapsed(original_func):
def wrapper(*args, **kwargs):
start = time.time()
result = original_func(*args, **kwargs)
end = time.time()
print("함수 수행시간: %f 초" % (end - start))
return result
return wrapper
@elapsed
def myfunc(msg):
print("'%s'을 출력합니다." % msg)
myfunc("You need python")
*args와 **kwargs는 데코레이터 함수가 기존 함수의 모든 인자를 처리할 수 있도록 해준다. 이렇게 하면 함수의 인자에 상관없이 데코레이터를 적용할 수 있다.
이 두 개념을 활용하면 코드의 모듈화와 재사용성이 높아지고, 함수의 기능을 더욱 유연하게 확장할 수 있다.
재귀호출(Recursive Call)이란, 함수 내부에서 자신을 다시 호출하는 방식을 말한다. 일반적인 상황에서는 잘 사용하지 않지만, 알고리즘을 구현할 때 매우 유용하게 쓰인다. 특정 알고리즘에 따라 반복문보다 재귀호출로 구현한 코드가 더 직관적이고 이해하기 쉬운 경우가 많다.
먼저 간단한 재귀호출 함수의 예시를 보자. 다음 코드를 IDLE의 소스 코드 편집 창에 입력하고 실행해보자.
def hello():
print('Hello, world!')
hello()
hello()
실행 결과:
Hello, world!
Hello, world!
Hello, world!
...(생략)
Traceback (most recent call last):
File "C:\project\recursive_function_error.py", line 5, in <module>
hello()
...
RecursionError: maximum recursion depth exceeded while pickling an object
hello 함수가 자기 자신을 계속 호출하고 있다. 실행 결과 'Hello, world!' 문자열이 반복적으로 출력되다가 RecursionError가 발생한다. 재귀호출을 사용할 때는 반드시 종료 조건을 만들어야 한다. 종료 조건 없이 계속해서 자기 자신을 호출하면 무한 루프에 빠지고, 결국 스택 오버플로우(stack overflow)로 인해 프로그램이 종료된다.
def hello(count):
if count == 0: # 종료 조건: count가 0이면 함수 호출을 멈춤
return
print('Hello, world!', count)
count -= 1 # count를 1 감소시킴
hello(count) # 감소된 count로 다시 hello 함수 호출
hello(5) # hello 함수 호출
실행 결과:
Hello, world! 5
Hello, world! 4
Hello, world! 3
Hello, world! 2
Hello, world! 1
이 코드에서는 hello 함수가 매개변수 count를 받아서, count가 0이 될 때까지 자신을 호출한다. count가 0이 되면 더 이상 함수 호출을 하지 않고 종료된다. count가 0이 아니면 'Hello, world!'와 현재 count 값을 출력하고, count를 1 감소시킨 후 다시 hello 함수를 호출한다.
이와 같이, 재귀호출에서는 종료 조건을 명확히 설정하여 무한 호출을 방지해야 한다.