[python] 클로저 사용하기

변수의 사용 범위 알아보기

# 변수의 사용 범위와 함수를 클로저 형태로 만드는 방법을 알아보자.
x = 10  # 전역 변수


def foo():
    print(x)  # 전역 변수 출력


foo()
print(x)  # 전역 변수 출력

# 변수 x는 foo 함수에서도, 함수 바깥에서도 x의 값을 출력할 수 있다.
# 이처럼 함수를 포함하여 스크립트 전체에서 접근할 수 있는 변수를 전역 변수라고 한다.
# 그리고 전역 변수에 접근할 수 있는 범위를 전역 범위라고 한다.


# 이번에는 함수 안에서 따로 변수를 만들어보자
def foo2():
    x = 20  # foo의 지역 변수
    print(x)  # foo의 지역 변수 출력


foo2()  # foo의 지역 변수인 x가 출력, 20
print(x)  # 전역 변수인 x가 출력, 10

# foo2 안의 x는 foo2 안에서 만들어졌기 때문에 foo2의 지역 변수이다.
# 따라서 지역 변수는 변수를 만든 지역 안에서만 접근할 수 있다.
# 지역 변수를 접근할 수 있는 범위를 지역 범위 라고 한다.


# 함수 안에서 전역변수에 접근하려면 global 키워드를 사용해야 한다.
def foo3():
    global x  # 전역 변수 x를 사용하겠다고 설정
    x = 30  # 전역 변수 x의 값을 변경
    print(x)  # 전역 변수 x 출력


foo3()
print(x)

# 파이썬에서 변수는 namespace에 저장된다.
# locals 함수를 사용하면 현재 네임스페이스를 딕셔너리 형태로 출력할 수 있다.
print(locals())


def foo4():
    x = 1
    print(locals())


foo4()

함수 안에서 함수 만들기

# 함수 안에서 함수를 만들려면 def로 함수를 만들고 그 안에서 다시 def로 함수를 만들면 된다.
# def 함수이름1():
#     코드
#     def 함수이름2():
#         코드
def print_hello():
    hello = 'Hello, world!'

    def print_message():
        print(hello)  # 바깥 함수의 지역 변수를 사용

    print_message()


print_hello()


# 현재 지역의 바깥쪽에 있는 지역 변수에 접근하려면 nonlocal 키워드를 사용한다.
def func1():
    x = 10

    def func2():
        nonlocal x
        x = 20

    func2()
    print(x)


func1()


# nonlocal은 현재 지역 기준 가장 가까운 지역의 변수를 찾는다
def foo1():
    x = 10
    y = 100
    def foo2():
        x = 20
        def foo3():
            nonlocal x  # foo2의 지역변수 x를 사용
            nonlocal y  # foo2에 y가 없으므로 한단계 더 밖으로 나가서 foo1의 y를 사용
            x = x + 30
            y = y + 300
            print(x, y)
        foo3()
    foo2()


foo1()

# global은 어느 지역이든 상관없이 무조건 전역 변수를 사용

클로저 사용하기

# 함수를 클로저 형태로 만드는 방법을 알아보자.
# 다음은 mul_add 자체를 반환하는 함수이다.
def calc():
    a = 3
    b = 5

    def mul_add(x):
        return a * x + b  # 함수 바깥의 지역변수 a, b를 사용해 계산

    return mul_add  # mul_add 함수를 반환


# 함수를 둘러싼 환경을 유지하다가 함수를 호출할 때 다시 꺼내서 사용하는 함수를 클로저
# 클로저에 속한 지역 변수는 바깥에서 직접 접근할 수 없으므로 데이터 숨기고 싶을 때 활용
# 여기서는 c에 저장된 함수가 클로저
c = calc()
print(c(1), c(2))  # 8 11


# 클로저는 다음과 같이 lambda로도 만들 수 있다.
def calc2():
    a = 3
    b = 5
    return lambda x: a * x + b  # 람다 표현식을 반환


c = calc2()
print(c(1), c(2), c(3))

# 클로저의 지역 변수를 변경하고 싶다면 nonlocal을 사용
def calc3():
    a = 3
    b = 5
    total = 0
    def mul_add(x):
        nonlocal total
        total = total + a * x + b  # 덧셈의 결과를 total에 누적
        print(total)
    return mul_add


c = calc3()
c(1)  # 8
c(2)  # 19

Updated:

Leave a comment