본문 바로가기

클로저

클로저는 함수 내 함수가 외부 함수의 변수를 참조하여 보존하는 것입니다. 데이터 은닉과 캡슐화에 활용되며, 데코레이터 구현의 기반이 됩니다.

1. 클로저

클로저는 파이썬에만 있는 개념이 아니라 다른 프로그래밍 언어에서도 중요한 프로그래밍 개념으로, 함수 내 함수가 외부 변수를 참조하여 보존하는 것을 얘기합니다.

# 1번: 클로저가 아닌경우
def outer_function():
    def inner_function():
        return 100 + 100
    return inner_function

# 2번: 클로저인 경우
def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

inner = outer_function(100)
inner(200) # inner 입장에서 100을 변경할 수 있는 방법이 없습니다.

위 1번 예제에서는 inner_function이 외부 변수를 참조하고 있진 않습니다. 함수를 반환하니 고차함수이지만, 클로저는 아닙니다.

2번 예제에서 outer_function은 inner_function을 반환합니다. inner_function은 외부 함수의 변수 x를 참조하고 있습니다. 따라서 outer_function(100)을 호출하면 x = 100이라는 상태를 기억하는 클로저가 만들어집니다.

여기서 눈여겨볼 점은 outer_function의 실행이 이미 끝났는데도 지역 변수 x가 사라지지 않는다는 것입니다. 그래서 inner(200)을 호출하면 기억해둔 100을 꺼내와 300을 돌려줍니다. 클로저가 inner_function의 코드뿐만 아니라 x = 100이라는 상태까지 함께 '기억'하고 있기 때문입니다.

실제로 어떤 값을 기억하고 있는지 들여다볼 수도 있습니다.

def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

inner = outer_function(100)
print(inner(200))                        # 300
print(inner.__closure__[0].cell_contents) # 100, 기억하고 있는 값

2. 클로저의 활용

클로저는 외부에서 직접 접근할 수 없는 변수를 '감추는' 방법을 제공합니다. 이를 통해 데이터 은닉과 캡슐화를 구현할 수 있습니다. 아래 코드에서 count 변수는 밖에서 직접 건드릴 수 없고, 오직 counter()를 호출하는 방법으로만 값을 늘릴 수 있습니다.

def make_counter():
    count = 0

    def counter():
        nonlocal count
        count += 1
        return count

    return counter

counter_a = make_counter()
print(counter_a())  # 1
print(counter_a())  # 2

위 코드에 등장한 nonlocal은 바깥 함수의 변수를 수정하겠다고 선언하는 키워드입니다. 바로 다음 장에서 자세히 다룹니다.

또한 클로저는 함수를 반환하기 때문에 함수형 프로그래밍과 데코레이터의 구현에 필수적입니다. 데코레이터는 nonlocal에 이어 설명하도록 하겠습니다.

클로저 - 견고한 파이썬 | 위니버시티