파이썬 네임스페이스와 스코프 이해하기

네임스페이스와 스코프 개념

네임스페이스란 무엇인가

변수를 선언할 때 내부적으로 어떤 일이 일어나는지 생각해보자.

username = 'leethon'

위 코드에서 할당 연산자의 우측에서는 문자열 'leethon'이라는 데이터 값이 생성되고, 메모리의 특정 영역에 저장된다. 이 데이터의 위치 정보는 변수명 username에 기록되어 관리된다.

그렇다면 변수명과 데이터 위치 정보는 어디에 저장될까? 바로 메모리 내의 특별한 공간인 네임스페이스에 저장된다. 네임스페이스는 변수명뿐만 아니라 함수명, 클래스명 등 모든 식별자를 저장하는 구조이다.

세 가지 주요 네임스페이스

  1. 빌트인 네임스페이스: 파이썬 인터프리터 수준에서 제공되는 이름들이 저장됨 (예: print, len, def 등)
  2. 글로벌 네임스페이스: 파이썬 파일 실행 시 생성되며, 해당 파일 내에서 정의된 변수, 함수, 클래스 등의 이름을 저장
  3. 로컬 네임스페이스: 함수 호출 시 생성되며, 해당 함수 내부에서 정의된 이름들을 저장

이 세 네임스페이스는 각각 독립된 메모리 공간으로 존재하며, 높은 수준의 네임스페이스일수록 더 넓은 범위에서 접근 가능하다.

생존 주기와 유효 범위

  • 생존 주기:
    • 빌트인: 파이썬 인터프리터 시작 시 생성, 종료 시 소멸
    • 글로벌: 스크립트 실행 시 생성, 실행 완료 시 소멸
    • 로컬: 함수 실행 시 생성, 함수 종료 시 소멸
  • 유효 범위:
    • 빌트인: 모든 파이썬 프로그램에서 사용 가능
    • 글로벌: 현재 실행 중인 파일 내에서 정의 이후 사용 가능
    • 로컬: 해당 함수 내부에서만 유효

식별자 검색 순서

동일한 이름이 여러 네임스페이스에 존재할 경우, 파이썬은 다음과 같은 우선순위로 이름을 검색한다:

  • 로컬 스코프에서 사용 시: 로컬 → 글로벌 → 빌트인
  • 글로벌 스코프에서 사용 시: 글로벌 → 빌트인

이 규칙 덕분에 함수 내부에서 정의한 변수가 글로벌 변수와 동일한 이름을 가져도 서로 간섭하지 않는다.

# 예제 1: 독립적인 로컬 네임스페이스
def function_a():
    data = 'jason'
    print(value)  

def function_b():
    value = 18
    print(data)
# 예제 2: 중첩 함수에서의 이름 검색
counter = 1
def outer_func():
    counter = 2
    def inner_func():
        # counter = 3
        print(counter)

    inner_func()
outer_func()

위 예제에서 counter 변수는 inner_func의 로컬 → outer_func의 로컬 순으로 찾아지며, print 함수는 빌트인 네임스페이스까지 탐색하여 찾게 된다.

global과 nonlocal 키워드

이 키워드들을 사용하면 기본적인 스코프 규칙을 우회하여 상위 네임스페이스의 값을 수정할 수 있다.

global 키워드 활용

score = 100
def update_score():
    global score  # 전역 변수 score를 참조하도록 선언
    score = 666   # 새로운 지역 변수가 아닌 전역 변수 수정

print(score)      # 100
update_score()
print(score)      # 666 - 전역 변수 값 변경됨

nonlocal 키워드 활용

total = 100
def parent_function():
    total = 200
    def child_function():
        nonlocal total  # 상위 함수의 total 변수 참조
        total = 300     # 상위 함수 변수 값 수정
        
    print(total)        # 200
    child_function()
    print(total)        # 300 - 상위 함수 변수 변경됨
    
parent_function()
print(total)            # 100 - 전역 변수는 영향 받지 않음

실습 문제

다음 코드들의 출력 결과를 예측하고 이유를 설명하라. global과 nonlocal을 사용해 결과를 변경해보자.

# 실습 1
balance = 100
def transaction():
    balance = 666	
transaction()
print(balance)
"""
출력: 100
이유: transaction 함수 내의 balance는 새로운 지역 변수로 생성되어 전역 balance에 영향을 주지 않음.
전역 변수 수정을 원한다면 함수 내에서 global balance 선언 필요.
"""

# 실습 2
balance = 100
def process_one():
    balance = 666
    def process_two():
        balance = 888
    process_two()
    print(balance)
process_one()
"""
출력: 666
이유: process_two 내의 balance는 새로운 지역 변수로 생성되어 상위 함수의 balance에 영향 없음.
상위 함수 변수 수정을 원한다면 process_two 내에서 nonlocal balance 선언 필요.
"""

태그: python namespace scope global nonlocal

5월 21일 15:52에 게시됨