Python

클로저

haventmetyou 2023. 10. 17. 16:22
변수의 사용 범위 알아보기
x = 10          # 전역 변수
def foo():
    print(x)    # 전역 변수 출력

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

foo 함수에서 함수 바깥에 있는 변수 x의 값 출력, 함수 바깥에서도 x의 값 출력 가능

함수를 포함해 스크립트 전체에서 접근할 수 있는 변수를 전역 변수라 하고, 전역 변수에 접근할 수 있는 범위를 전역 범위라고 함

 

함수 안에서 전역 변수 변경

def foo():
    x = 10      # 지역 변수
    print(x)    # 지역 변수 출력

foo()           # 함수 호출 
print(x)        # 에러, foo의 지역 변수는 출력할 수 없음
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined


x = 10
def foo():
    x = 20
    print(x)

foo()
20
print(x)
10


x = 10        # 전역 변수
def foo():
    global x    # 전역 변수 x를 사용하겠다 설정
    x = 20      # x는 전역 변수
    print(x)    # 전역 변수 출력

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


# x = 10        # 전역 변수
def foo():
    global x
    x = 20      # 지역 변수
    print(x)

foo()
20
print(x)
20

 

네임스페이스

변수는 네임스페이스(namespace, 이름공간)에 저장됨

> locals 함수를 사용하면 현재 네임스페이스를 딕셔너리 형태로 출력

>>> # 전역 범위에서 네임스페이스 출력
>>> x = 10
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'foo': <function foo at 0x0000019720A4CC20>, 'x': 10}
>>>
>>>
>>> # 함수 안에서 locals 사용
>>> def foo():
...     x = 10
...     print(locals())
...
>>> foo()
{'x': 10}

 

함수 안에서 함수 만들기
def print_hello():
    hello = 'Hello, world!'
    def print_messeage():
        print(hello)
    print_messeage()

print_hello()
Hello, world!

지역 변수 범위

def A():
    x = 10    # A의 지역변수
    def B():
        x = 20

    B()
    print(x)

A()
10


def A():
    x = 10    # A의 지역변수
    def B():
        x = 20
        print(x)
        
    B()
    print(x)    # 20 출력

A()             # 10 출력

지역 변수 변경

nonlocal 지역변수

def A():
    x = 10    # A의 지역변수
    def B():
        nonlocal x    # 현재 함수의 바깥쪽에 있는 지역 변수 사용
        # global x
        x = 20        # A의 지역 변수 x에 20 할당

    B()
    print(x)

A()
20

# nonlocal이 변수 찾는 순서
def A():
    x = 10    # A의 지역변수
    y = 100
    def B():
        x = 20
        def C():
            nonlocal x
            nonlocal y
            x = x + 30
            y = y + 300
            print(x)
            print(y)
        C()
    B()
    
A()
50
400

 

global로 전역 변수 사용

함수가 몇 단계든 상관없이 global 키워드를 사용하면 무조건 전역 변수 사용

x = 1
def A():
    x = 10 
    def B():
        x = 20
        def C():
            global x
            x = x + 30
            print(x)
        C()
    B()
A()
31

 

클로저 사용
def clac():
    a = 3
    b = 5
    def mul_add(x):
        return a * x + b
    return mul_add

c = clac()
print(c(1), c(2), c(3), c(4), c(5))
8 11 14 17 20

함수를 둘러싼 환경(지역 변수, 코드 등)을 계속 유지하다가 함수를 호출할 때 다시 꺼내서 사용하는 함수를 클로저(closure)라고 함

위에서는 c에 저장된 함수가 클로저

클로저를 사용하면 프로그램의 흐름을 변수에 저장 > 지역 변수와 코드를 묶어서 사용하고 싶을 때 활용

클로저에 속한 지역 변수는 바깥에서 직접 접근할 수 없으므로 데이터를 숨기고 싶을 때 활용

 

람다로 클로저 만들기

def clac():
    a = 3
    b = 5
    return lambda x: a * x + b

c = clac()
print(c(1), c(2), c(3), c(4), c(5))

클로저의 지역 변수 변경하기

def clac():
    a = 3    # 함수 calc의 지역 변수
    b = 5
    total = 0
    def mul_add(x):
        nonlocal total
        total = total + a * x + b
        print(total)
    return mul_add

c = clac()
c(1)
8
c(2)
19
c(3)
33