2. 함수의 변수 스코프 (Scope)
함수는 내부에 자신만의 독립적인 방(스코프)을 가지고 있습니다. 이를 통해 함수 안팎에서 동일한 이름의 변수들을 사용해도 서로 엉키지 않게 막아줍니다.
파이썬이 함수 내부에서 변수를 찾고 관리하는 규칙인 네임스페이스(Namespace)와 스코프(Scope)의 개념을 명확히 이해해야만 예상치 못한 버그를 막을 수 있습니다.
2.1 파이썬의 변수 탐색 규칙 (LEGB 룰)
파이썬의 모든 변수 이름표들은 거대한 딕셔너리(사전) 구조인 네임스페이스 속에서 관리됩니다. 프로그램이 특정 변수 이름을 만나면, 다음의 순서대로 방을 뒤져가며 값을 찾습니다.
- Local (지역): 함수 내부의 가장 깊은 방. 함수가 호출될 때 생성되고 끝나면 파괴됩니다.
- Enclosing (내포): (나중에 배울 내부 함수의 경우) 나를 감싸고 있는 바깥쪽 함수의 방.
- Global (전역): 파일(모듈) 전체 영역. 스크립트가 실행될 때 생성됩니다.
- Built-in (내장): 파이썬이 기본으로 제공하는 최상위 공간 (
print,len등의 내장 함수가 위치함).
[!TIP] 즉, 내 방(Local)에 찾는 물건이 없으면 거실(Global)로 나가보고, 거실에도 없으면 집 밖(Built-in)을 뒤지는 식입니다. 끝까지 찾아도 없으면
NameError로 프로그램이 뻗어버립니다.
# ================= Global (전역) 공간 =================
power = 100
def my_func():
# ================= Local (지역) 공간 =================
power = 50
print(power) # 내 방(Local)에 'power'가 있으므로 50이 출력!
my_func()
print(power) # 거실(Global)의 입장에서는 방 안을 볼 수 없으므로 여전히 100
2.2 함수 내부에서 전역 변수 조작하기 (global)
함수 안에서는 밖(Global)에 있는 변수의 “값을 읽어오기(조회)”는 마음대로 할 수 있습니다. 하지만 변수에 새로운 값을 담아버리는 “수정 및 갱신(할당)”은 기본적으로 철저히 금지되어 있습니다. 갱신을 시도하는 순간, 파이썬은 그것을 수정이 아닌 ‘동일한 이름의 내 방(Local) 변수 생성’으로 간주해버리기 때문입니다.
이를 무시하고 함수 내부에서 바깥의 변수를 강제로 조종하고 싶을 때 사용하는 치트키가 바로 global 키워드입니다.
character_hp = 500 # 전역 변수
def take_damage(damage):
# "이 함수 안에서 쓰이는 character_hp는 내 방(Local) 것이 아니라, 밖에 있는 놈이다!" 선언
global character_hp
# 이제 자유롭게 바깥 변수를 깎아내릴 수 있습니다.
character_hp = character_hp - damage
take_damage(150)
print(character_hp) # 350 (전역 변수의 값이 실제로 깎임!)
[!WARNING]
global키워드를 남발하면 코드가 조금만 복잡해져도 도대체 어디서 변수가 꼬여버렸는지 예측하기가 매우 힘들어집니다. 피치 못할 때만 사용하고, 가급적 함수의 반환값(return)을 통해 외부 데이터를 다루는 것이 올바른 객체지향적 설계입니다.
2.3 locals()와 globals()
현재 내 위치를 기준으로, 어떠한 변수들과 함수들이 활동 중인지를 투명하게 들여다볼 수 있는 파이썬 내장 탐지 함수들입니다. (둘 다 딕셔너리 형태로 값을 뱉어냅니다)
locals(): 지금 내가 있는 이 지역 방 안의 상태 창을 띄웁니다.globals(): 거실(전역 모듈 전체)의 상태 창을 띄웁니다.
x = 10
def check_namespaces():
y = 20
print("--- 내 방(Local) ---")
print(locals()) # {'y': 20} (바깥의 x는 보이지 않음)
check_namespaces()
print("--- 거실(Global) ---")
# 수많은 기본 시스템 변수들과 함께, 내가 만든 x와 check_namespaces 가 들어있습니다.
print(globals())