상위 목록: 하위 목록: 작성 날짜: 읽는 데 17 분 소요

클로저(Closure)

클로저(Closure)란 함수가 내부 함수를 포함하고 있는 형태를 의미하며, 내부 함수 밖에 있는 외부 함수지역 변수를 참조하는 형태입니다.

외부 함수가 종료되어도 내부 함수의 지역 변수는 사라지지 않고 내부 함수에서 사용할 수 있습니다.

클로저의 정의는 다음과 같은 조건을 만족해야 합니다.


  1. 중첩 함수(Nested Function) 형태
  2. 내부 함수외부 함수의 지역 변수를 참조하는 형태
  3. 외부 함수내부 함수를 반환하는 형태


클로저를 사용하면, 전역 변수의 사용을 최소화할 수 있으며, 데이터를 은닉하여 지속성을 보장할 수 있습니다.

또한, 접근할 수 없는 범위의 데이터를 접근해 사용할 수 있습니다.



클로저(Closure) 사용하기

def outer_func(x):

    total = x

    def inner_func(y):
        return total + y

    return inner_func


main = outer_func(1)
sub1 = main(2)
sub2 = main(3)
sub3 = main(4)
print(sub1, sub2, sub3)
결과
3 4 5

main 변수에 outer_funcx(total) 값을 1로 정의하고, inner_func를 반환합니다.

main 변수에 inner_func가 할당되며, inner_funcy 값을 각각 2, 3, 4로 할당합니다.

inner_func 함수 기준에서 total 변수는 함수의 바깥 범위에 있지만, 결과에서 확인할 수 있듯이 참조가 가능한 형태입니다.

total 변수는 inner_func에서 사용되지만, 전역 변수도 아니며 inner_func 내부에서 정의하지 않은 변수입니다.

이 변수를 자유 변수(free variable)라 합니다.


중첩 함수(Nested Function)가 아닌 형태에서는 전역 변수를 사용하게 되어, 코드가 복잡해질 경우 어디서 변경되었는지 확인하기 어려워집니다.

이를 방지하고자 클로저(Closure)를 사용합니다. 즉, 전역 변수 대신에 자유 변수를 사용합니다.



지역 변수(local variable) 참조

def outer_func():
    value = 0

    def inner_func():
        value = 100

    inner_func()
    return value


func = outer_func()
print(func)
결과
0

outer_func 함수에서 정의된 value 변수를 inner_func에서 변경을 시도한다면, 값이 정상적으로 변경되지 않습니다.

위의 코드를 작성할 경우, Unused variable 'value' 형태의 문제가 발생합니다.

이는, inner_func 함수에서 value 변수가 재정의됐다는 의미가 됩니다.

위 코드에서 value 변수는 outer_func 함수의 valueinner_func 함수의 value로 두 가지가 정의된 형태입니다.

만약, 외부 함수지역 변수를 수정하려면, 다음과 같이 사용합니다.


def outer_func():
    value = 0

    def inner_func():
        nonlocal value
        value = 100

    inner_func()
    return value


func = outer_func()
print(func)
결과
100

nonlocal value의 형태로 사용하면, 내부 함수value지역 변수로 새로이 생성되지 않고, 외부 함수value로 인식합니다.

nonlocal 키워드는 가장 빨리 만나는 상위 변수인 0을 참조하게 됩니다.

중첩이 더 깊어질 경우, 한 계단씩 올라가면서 변수를 찾게됩니다.



지역 변수(local variable) 변경

def outer_func():
    var = list()

    def inner_func(value):
        var.append(value)
        return var

    return inner_func


main = outer_func()
result = main({"A": 65})
print(result)
result = main({"B": 66})
print(result)
결과
[{‘A’: 65}]
[{‘A’: 65}, {‘B’: 66}]

외부 함수의 지역 변수를 변경하게 되면, 값이 지속적으로 유지됩니다.

클로저를 통해서 전역 변수를 사용하지 않고, 외부 함수자유 변수를 통해서도 구현이 가능합니다.



자유 변수(free variable)와 셀(cell)

def outer_func():
    var = list()

    def inner_func(value):
        var.append(value)
        return var

    return inner_func


main = outer_func()
result = main({"A": 65})
result = main({"B": 66})
print(main.__closure__)
print(type(main.__closure__), len(main.__closure__))
print(main.__closure__[0].cell_contents)
결과
(<cell at 0x00000157B5967708: list object at 0x00000157B599D508>,)

<class ‘tuple’> 1
[{‘A’: 65}, {‘B’: 66}]

속성(attributes) 중 하나인 __closure__를 통해 자유 변수를 확인할 수 있습니다.

클로저 속성은 셀(cell) 형태로 스코프(Scope)에서 참조하는 변수를 보여줍니다.

스코프(Scope)정의된 변수가 보이는 유효 범위를 의미합니다.

즉, main 함수의 outer_func 함수 내에서 정의된 변수를 보여줍니다.

변수는 중복될 수 없으므로, 튜플의 형태를 가지며, 자유 변수의 개수만큼 길이를 가집니다.

외부 함수의 자유 변수의 개수는 1개이므로, 셀의 0 번째 값에 var 변수가 담겨있습니다.

main.__closure__[0]0 번째 셀을 출력합니다.

실제 값을 확인하기 위해서는 cell_contents를 사용해 자유 변수의 값을 확인할 수 있습니다.

댓글 남기기