Unit 35. 클로저 사용하기

이번에는 변수의 사용 범위와 함수를 클로저 형태로 만드는 방법을 알아보겠습니다.

참고로 클로저는 개념이 다소 어려울 수 있으므로 변수의 사용 범위부터 알아본 뒤에 설명하겠습니다.

35.1 변수의 사용 범위 알아보기

파이썬 스크립트에서 변수를 만들면 다음과 같이 함수 안에서도 사용할 수 있습니다.

global_variable.py

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

실행 결과

10
10

foo 함수에서 함수 바깥에 있는 변수 x의 값을 출력했습니다. 물론 함수 바깥에서도 x의 값을 출력할 수 있습니다. 이처럼 함수를 포함하여 스크립트 전체에서 접근할 수 있는 변수를 전역 변수(global variable)라고 부릅니다. 특히 전역 변수에 접근할 수 있는 범위를 전역 범위(global scope)라고 합니다.

그림 35-1 전역 변수와 전역 범위
그림 35 1 전역 변수와 전역 범위

그럼 변수 x를 함수 foo 안에서 만들면 어떻게 될까요?

local_variable.py

def foo():
    x = 10      # foo의 지역 변수
    print(x)    # foo의 지역 변수 출력
 
foo()
print(x)        # 에러. foo의 지역 변수는 출력할 수 없음

실행 결과

10
Traceback (most recent call last):
  File "C:₩project₩local_variable.py", line 6, in <module>
    print(x)        # 에러. foo의 지역 변수는 출력할 수 없음
NameError: name 'x' is not defined

실행을 해보면 x가 정의되지 않았다는 에러가 발생합니다. 왜냐하면 변수 x는 함수 foo 안에서 만들었기 때문에 foo의 지역 변수(local variable)입니다. 따라서 지역 변수는 변수를 만든 함수 안에서만 접근할 수 있고, 함수 바깥에서는 접근할 수 없습니다. 특히 지역 변수를 접근할 수 있는 범위를 지역 범위(local scope)라고 합니다.

그림 35-2 지역 변수와 지역 범위
그림 35 2 지역 변수와 지역 범위

이렇게 전역 변수와 지역 변수를 사용해보았습니다.

만약 함수 안에서 전역 변수의 값을 변경하면 어떻게 될까요?

global_local_variable.py

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

실행 결과

20
10

분명 함수 foo 안에서 x = 20처럼 x의 값을 20으로 변경했습니다. 하지만 함수 바깥에서 printx의 값을 출력해보면 10이 나옵니다. 겉으로 보기에는 foo 안의 x는 전역 변수인 것 같지만 실제로는 foo의 지역 변수입니다. 즉, 전역 변수 x가 있고, foo에서 지역 변수 x를 새로 만들게 됩니다. 이 둘은 이름만 같을 뿐 서로 다른 변수입니다.

함수 안에서 전역 변수의 값을 변경하려면 global 키워드를 사용해야 합니다. 다음과 같이 함수 안에서 global에 전역 변수의 이름을 지정해줍니다.

  • global 전역변수

function_global_keyword.py

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

실행 결과

20
20

이제 함수 안에서 x를 20으로 변경하면 함수 바깥에서 x를 출력했을 때 20이 나옵니다. 이렇게 함수 안에서 global에 변수를 지정하면 전역 변수를 사용하게 됩니다.

만약 전역 변수가 없을 때 함수 안에서 global을 사용하면 해당 변수는 전역 변수가 됩니다.

# 전역 변수 x가 없는 상태
def foo():
    global x    # x를 전역 변수로 만듦
    x = 20      # x는 전역 변수
    print(x)    # 전역 변수 출력
 
foo()
print(x)        # 전역 변수 출력
참고 | 네임스페이스

파이썬에서 변수는 네임스페이스(namespace, 이름공간)에 저장됩니다. 다음과 같이 locals 함수를 사용하면 현재 네임스페이스를 딕셔너리 형태로 출력할 수 있습니다.

>>> x = 10
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'x': 10}

출력된 네임스페이스를 보면 'x': 10처럼 변수 x와 값 10이 저장되어 있습니다. 여기서는 전역 범위에서 네임스페이스를 출력했으므로 전역 네임스페이스를 가져옵니다.

마찬가지로 함수 안에서 locals를 사용할 수도 있습니다.

>>> def foo():
...     x = 10
...     print(locals())
...
>>> foo()
{'x': 10}

네임스페이스를 보면 'x': 10만 저장되어 있습니다. 이때는 지역 범위에서 네임스페이스를 출력했으므로 지역 네임스페이스를 가져옵니다.