반응형

1. Local 변수

Local 변수는 함수 안에서 정의되며, 해당 함수의 scope(범위) 내에서만 접근 가능한 변수이다. 함수 실행 중에만 존재하고, 함수 종료와 함께 메모리에서 제거된다.

Local 변수의 특징

1. Scope: local 변수가 정의된 함수 내로 제한된다.

2. Lifetime: 함수의 실행 중에만 존재한다.

3. 재정의: 이미 같은 이름의 global 변수가 있다고 해도 local 변수를 정의할 수 있다. 함수 내의 local 변수는 함수 scope 내에서 잠시 global 변수 이름을 shadowing한다.

Local 변수 예시

def f():
    a = 10  # Local 변수
    print(a)


f()
print(a)
10
Traceback (most recent call last):
    print(a)
NameError: name 'a' is not defined

Local 변수로서의 a는 잘 출력되지만, 함수 밖에서는 같은 이름으로 변수에 접근할 수 없다.

 

Local 변수의 이름 재정의 및 shadowing 상황 예시

a = "global"

def f():
    a = "local"
    print(a)  # local 변수를 가리킨다

f()
print(a)  # global 변수를 가리킨다
local
global

함수 내에 선언된 local 변수 a가, 바깥의 global 변수 a를 (함수 내에서는) 가려버리고 있음을 알 수 있다.

 

2. Global  변수

Global 변수는 함수, 클래스, 및 block 바깥에서 정의되며, 전체 스크립트 파일 모든 곳에서 접근이 가능하다. 

또한 함수 내에서도 접근이 가능하다(local 변수에 의해 shadow 되지 않은 상태여야 함).

Global 변수는 특정 scope에 제약받지 않으며, 프로그램 동작 중에는 계속해서 메모리 상에 유지된다.

1. Scope: 전체 프로그램에서 모두 접근 가능하다.

2. Lifetime: 프로그램의 실행 중에 존재한다. 그러나 명시적으로 delete하면 삭제된다.

3. 수정: 함수 내에서 global 변수를 수정하고자 한다면, 함수 내에서 해당 변수를 "global"로 정의해야 한다.

 

3. global 키워드

함수 내에서 global 변수 접근 예시

x = 10  # Global 변수

def f():
    print(x) # Global 변수에 접근

f()
10

함수 내에서 global 변수에 접근해서 읽기만 할 때는 global 키워드를 따로 사용하지 않아도 된다. 

 

함수 내에서 gloabl 변수를 수정 예시

a = 10  # Global 변수

def f():
    global a
    a = 50 # Global 변수 수정
    print(a)

f()
print(a)
50
50

global 키워드를 사용해서, 함수 내에서 global 변수에 접근해 값을 수정했음을 알 수 있다.

위 예시에서는 local 변수가 전혀 사용되지 않았다.

 

4. 다소 어려울 수 있는 케이스

그렇다면 아래 케이스도 살펴 보자. 

a = 100

def f():
    print(a)
    a = a + 1
    return a
    
print(f())
print(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
UnboundLocalError: cannot access local variable 'a' where it is not associated with a value

global 키워드를 사용하진 않은 상태인데,  함수 내의 print(a) 에서 UnboundLocalError 에러가 발생한다. 

UnboundLocalError  에러가 발생하는 이유는, a = a + 1이라는 대입문이 있으므로, 파이썬은 a를 대입문에서 새로 정의되는 local 변수로 간주하기 때문이다. local 변수인 a가 어떤 값을 가지기 전에 print(a)에서 a에 접근하므로 위의 UnboundLocalError가 발생한다.

하지만 여기서 드는 의문 점은, "print(a)에서 사용하는 a는 local 변수가 아닌, global 변수 a이므로 100의 값을 갖지 않는가?"인 점이다.

비록 global 키워드를 사용하지는 않았지만, print(a) 자체는 global 변수 a를 수정하지 않았기 때문에 이런 의문이 드는 것이다.

즉 a = a + 1은 print(a)보다 뒤쪽에 있는데 이것을 통해 a가 수정된다는 점을 파이썬이 미리 파악해서, a를 수정하지 않는 print(a) 문이 접근하는 a는 local 변수인 것으로 간주해버린다는 것이다. 작동 원리의 이해가 다소 어려운 문제이다.

 

핵심 포인트: Scope Resolution

파이썬에서 local 변수는 함수의 컴파일 단계에서 결정된다. 그 말은 파이썬은 컴파일 시점에  a = a + 1 문을 보고, 함수 전체에서 a 가 지역 변수라는 사실을 결정해버린다는 뜻이다. 

파이썬은 변수들의 scope를 함수의 정의 시점에 정적으로 결정하며, 실행 시점에 동적으로 결정하지 않는다. 이것이 변수의 scope resolution이다. 

1. 컴파일 단계:

파이썬이 a = a + 1 문을 함수 바디에서 발견한다.

a를 함수 전체에 대해서 local 변수인 것으로 마크한다.(a = a + 1 문 이전에 a를 사용하는 코드가 있더라도)

2. 실행 단계:

함수 실행시, print(a)가 a에 접근한다.

파이썬이 local 변수인 a를 찾아내는데, 아직 a = a + 1이 실행되지 않았으므로 a가 초기화되지 않은 상태임을 확인한다.

그러므로 UnboudLocalError를 발생시킨다.

 

위 문제를 해결하려면, 2가지 방법이 있다.

1. global 변수 a를 사용한다.

a = 100

def f():
	global a
    print(a)
    a = a + 1
    return a
    
print(f())
print(a)
100
101
101

 

2. local 변수 a를 사용한다.

def f():
    a = 100  # Local 변수
    print(a)
    a = a + 1
    return a

print(f())
100
101

 

반응형

+ Recent posts