파이썬 변수 스코프 : 기초지만 너무 중요한

파이썬에서 변수의 유효 범위 (“스코프”)는 해당 변수가 언제 어디서 사용 가능한지를 나타냅니다. 기초에서 배우지만 아차하면 향후 프로그래밍 중에 치명적 오류가 될 수 있으므로 주의해야 합니다.

(특히 mutable 자료형과 immutable 자료형 사용 시 객체 참조가 달라지므로 유의해야 합니다. 아래 설명 참고)

이번 포스트에서는 전역 범위, 지역 범위의 정의와 예제 그리고 주의해야 할 점에 대해 정리해보았습니다.

전역 스코프 (Global Scope)

전역 범위코드의 가장 바깥쪽에 정의된 변수들을 말합니다.
전역 변수는 모든 함수에서 접근 가능하지만, 함수 내에서 전역 변수를 수정하려면 global 키워드를 사용해야 합니다.

함수 내에서 전역변수 사용

global_variable = 10

def my_function():
    print(global_variable)  # 10
    print(id(global_variable))  # 140721475667016

my_function()
print(global_variable)  # 10
print(id(global_variable))  # 140721475667016

함수 내에서 global 없이 전역변수 변경

함수 내에서 global 선언 없이 전역변수를 변경 해봅니다.

결과를 보면 함수 내에서 변경한 값이 전역변수에 적용이 되지 않은 것을 볼 수 있습니다.

또한 변수의 ID도 다른 것을 확인 할 수 있습니다.

이는 함수 내에서 전역 변수명과 동일한 변수를 바꿀 시, 전역 변수의 재할당이 아니라 별개의 새로운 객체의 선언 및 할당이라는 것을 의미합니다.

global_variable = 10

def my_function():
    global_variable = 20
    print(global_variable)  # 20
    print(id(global_variable))  # 140721475667336

my_function()
print(global_variable)  # 10
print(id(global_variable))  # 140721475667016

함수 내에서 global 전역 변수 수정

함수 내에서 전역 변수를 변경할 때 global을 사용하면 실제 전역 변수가 변경됩니다.

global_variable = 10

def my_function():
    global global_variable
    global_variable = 20
    print(global_variable)  # 20
    print(id(global_variable))  # 140721475667336

my_function()
print(global_variable)  # 20
print(id(global_variable))  # 140721475667336

주의사항 : global 없이 함수 내에 전역변수 사용

위에서 언급한 것 처럼, global을 사용하지 않고 함수 내에서 전역변수와 동일한 변수를 사용하면 이는 변수명이 동일해도 새로운 객체입니다.
5번 줄의 global_variable은 새로운 지역변수가 되고 지역변수가 선언되기 전에 print 함수에서 변수를 사용했으므로 UnboundLocalError 가 발생합니다.

global_variable = 10

def my_function():
    print(global_variable)  # UnboundLocalError
    global_variable = 20

my_function()
print(global_variable)

mutable 자료형이 전역변수일 때

mutable한 자료형(예: 리스트, 딕셔너리)의 경우 전역 변수를 함수 내에서 수정할 때, 해당 전역 변수는 함수 호출 후에도 변경된 값을 유지하게 됩니다. 이는 mutable한 자료형이 함수 내에서 참조되기 때문입니다.

global_variable = {'key1': 'value1', 'key2': 'value2'}


def my_function():
    global_variable['key1'] = 'value10'
    print(global_variable)  # {'key1': 'value10', 'key2': 'value2'}
    print(id(global_variable))  # 1274882135296


my_function()
print(global_variable)  # {'key1': 'value10', 'key2': 'value2'}
print(id(global_variable))  # 1274882135296

하지만 이때 조심해야 하는 점은 mutable 자료형이라도 변수를 재할당하는 것과 같이 작성하면 이는 함수 내에서의 global_variable를 새로운 객체로 참조하게 된다는 것입니다. 때문에 이때 변수는 전역 변수와는 별개의 객체가 됩니다.

global_variable = {'key1': 'value1', 'key2': 'value2'}

def my_function():
    global_variable = {'key3': 'value3', 'key4': 'value4'}
    print(global_variable)  # {'key3': 'value3', 'key4': 'value4'}
    print(id(global_variable))  # 1968484023424

my_function()
print(global_variable)  # {'key1': 'value1', 'key2': 'value2'}
print(id(global_variable))  # 1968482587904

지역 스코프 (Local scope)

지역 범위함수 내에서 정의된 변수들을 말합니다.
함수 내에서 정의된 변수는 해당 함수 내에서만 접근 가능합니다.

def my_function():
    local_variable = 20
    print(local_variable)

my_function()  # 출력: 20
# print(local_variable)  # 오류: NameError - local_variable이 정의되지 않았습니다.

자바스크립트의 scope와 비교

정말 다행히도 파이썬의 스코프 개념은 자바스크립트 보다 훨씬 단순합니다. 자바스크립트는 블록 스코프라는 개념이 있으며 var, let, const 키워드에 따라 다른 스코프를 따르는 정말 골치 아픈 점이 존재합니다…

파이썬은 블록 스코프를 갖지 않고, 대신 로컬 스코프와 전역 스코프만 갖는 언어입니다.

if True:
    x = 10  # 블록 내에서 선언되었지만 함수 스코프를 가짐

def my_function():
    print(x)  # 함수 내에서 x를 사용할 수 있음

my_function()
print(x)  # 전역 스코프에서도 x를 사용할 수 있음

위의 코드에서 xif 문 블록 내에서 선언되었지만, 함수 my_function() 내부에서도 사용할 수 있으며, 전역 스코프에서도 사용할 수 있습니다. 이는 파이썬에서 함수 스코프가 블록 스코프를 대체하는 특성입니다.

블록 스코프 개념을 가지고 있는 자바스크립트

자바스크립트는 로컬 스코프(“함수 스코프”라고 부름)외에 블록 스코프 라는 개념이 존재 합니다.

말 그대로 {} (조건문에서 사용되는 블록) 에서의 스코프를 말합니다. 하지만 혼동을 줄 수 있는 점은 동일하게 블록 내에서 선언한 변수라도 어떤 키워드를 사용하느냐에 따라 스코프가 달라진다는 사실입니다.

if (true) {
    var funcVar = "I'm in a block! but have function scope!!!";
    // var는 함수 스코프를 가짐 -> 블록 내/외에서 유효
    console.log(funcVar); //output: I'm in a block! but have function scope!!!
}
// 함수 스코프는 블록 스코프보다 크기 때문에 블록을 벗어나도 사용할 수 있습니다.
console.log(funcVar);  //output: I'm in a block! but have function scope!!!
if (true) {
    let funcVar = "I'm in a block! and have block scope!!!";
    // let은 블록 스코프를 가짐 -> 블록 내에서만 유효
    console.log(funcVar); //output: I'm in a block! and have block scope!!!
}
// 블록을 벗어나면 해당 변수는 유효하지 않음
console.log(funcVar);  //ReferenceError: funcVar is not defined

키워드가 var, let 인가에 따라 스코프가 달라지는 것을 확인해주세요. var는 함수 스코프를 갖기 때문에 블록 스코프 내에서 선언해도 외부에서 사용할 수 있습니다. let 은 블록 스코프를 갖기 때문에 블록 외에서 사용할 수 없는 것을 볼 수 있습니다.

참고하면 좋은 글

Leave a Comment

목차