◼ IT Etc./Python

[Python] 변수 Scope (전역 변수와 지역 변수) 에 대한 이해

SangYoonLee (SYL) 2023. 2. 2. 11:23
반응형

예시 1

_list = [1, 2, 3, 4]


def sum_all():
    sum_val = 0
    for elem in _list:
        sum_val += elem

    return sum_val


total_sum = sum_all()
print(total_sum)
print(sum_val)
10
NameError: name 'sum_val' is not defined
  • 전역 변수는 굳이 인자로 넘기지 않아도 함수 내에서 잘 작동한다. 즉, 전역 변수는 어디에서나 쓸 수 있다.
  • 지역 변수는 내부 Scope를 벗어나면 증발하여 더 이상 접근할 수 없다. 즉, 지역 변수는 어디에서나 쓸 수 없다.

 

예시 2

코드 1.

_list = [1, 2, 3, 4]


def modify():
    _list[0] = 10


modify()
for elem in _list:
    print(elem, end=" ")
10 2 3 4
  • list는 mutable한 객체이므로, 전역 변수로 선언되었을 때 함수 내부에서 값을 참조하고 수정해도 원본에 반영된다.
  • 위의 코드에서 modify() 함수 내부의 _list 변수는 외부에 선언된 전역 변수 _list로 인식된다.

 

코드 2.

_list = [1, 2, 3, 4]


def modify():
    _list = [5, 6, 7, 8]


modify()
for elem in _list:
    print(elem, end=" ")
1 2 3 4
  • 반면, 위의 코드에선 modify() 함수 내부의 _list가 재정의 되었으므로, python에선 이를 새로운 지역 변수로 인식한다.
  • 따라서 modify() 함수가 끝나는 순간 (새로 생성됐던) 함수 내부의 _list 객체는 소멸하고, 외부에 선언된 전역 변수 _list만 남게 된다.

 

  • 만일 modify() 함수 내부의 _list를 전역 변수로 인식하도록 하려면, 다음처럼 함수 안에 global 표식을 해주어야 한다.
_list = [1, 2, 3, 4]


def modify():
    global _list
    _list = [5, 6, 7, 8]


modify()
for elem in _list:
    print(elem, end=" ")
5 6 7 8
  • 원래 원칙은, 전역 변수를 함수 내에서 쓰려면 함수 안에 global 표식을 해줘야 한다.
  • 하지만 모르거나 귀찮아서 보통 잘 쓰지 않는다. 평소에 안 써도 무방하다.

 

예시 3

코드 1.

num = 10


def modify():
    print(num)


modify()
10
  • 전역 변수를 함수 내부에서 값을 끌어다 쓰는 것은 모두 허용된다.

 

코드 2.

num = 10


def modify():
    num = 5
    print(num)


modify()
print(num)
5
10
  • 10, 5는 immutable한 객체이다.
  • 따라서 함수 외부와 내부에 같은 이름의 변수 num을 선언하면
    • 함수 내부에서 num을 출력할 땐 지역 변수 num의 값 5를 출력하고 (내부 변수가 외부 변수를 가림)
    • 함수 밖에서 num을 출력할 땐 전역 변수의 num 값 10을 출력하는 것이다.

 

코드 3.

num = 10


def modify():
    num += 5


modify()
print(num)
UnboundLocalError: local variable 'num' referenced before assignment
  • 이 코드에선 왜 이러한 에러가 발생하는지 이해해보자.
  • num += 5  num = num + 5와 동일한 코드이다.
  • 이를 반영하여 코드를 다시 작성하면 아래와 같다.
num = 10


def modify():
    num = num + 5
   (1번)  (2번)


modify()
print(num)
  • modify() 함수 내의 (1번) num이 새롭게 정의되었으므로 이는 New 지역 변수로 인식된다.
  • 따라서 (2번) num도, 전역 변수의 num이 아닌, 새로운 지역 변수로 인식된다.
  • 이 지역 변수 (2번) num은 값이 아직 할당이 되지 않았기 때문에 위와 같은 에러가 발생하는 것이다.

 

  • 이를 해결하고자 한다면, 함수 내에 global 표식을 붙여 modify() 함수 내 num을 전역 변수 num으로 인식되도록 해주면 된다.
 
num = 10


def modify():
    global num
    num += 5


modify()
print(num)
15

 

 정리

  • 전역 변수로 선언된 immutable 객체를 함수 내에서 바꾸고 더하는 작업을 하려면, global 표식을 해주어야 한다.
  • 전역 변수로 선언된 mutable 객체를 함수 내에서 바꾸고 더하는 작업을 하려면, 객체 특성 상 그냥 갖다 써도 상관 없다.
  • 대신 함수 내에서 전역 변수와 같은 이름으로 변수를 재정의 한다면, immutable 객체든 mutable 객체든 재정의된 변수는 새로운 지역 변수로 인식된다. 이렇게 되기 싫으면 global 표식을 해주면 된다.

 

(+) 참조 가능한 값이 여러 가지일 때

a, b = 10, 20


def modify(a, b):
    print(a, b)  # (1번)
    print_a_and_b()
    a, b = b, a
    print(a, b)


def print_a_and_b():
    print(a, b) # (2번)


modify(50, 60)
print_a_and_b()
50 60
10 20
60 50
10 20
 
  • (1번)에서의 a, b는 전역 변수의 a, b (10, 20)를 참조하는 것도 가능하고 인자 값 (50, 60)을 참조하는 것도 가능하다.
  • 이렇게 참조할 수 있는 값이 여러 가지일 땐, 가장 가까이에 있는 값을 참조한다.
  • 즉, (1번)에서 a는 50을 가리키고, b는 60을 가리킨다.
  • (2번)의 경우, a, b는 전역 변수 a, b밖에 참조할 값이 없으므로 각각 10, 20을 가리킨다.

 

참고 자료 : Code Tree, Python - 변수의 특징(mutable, immutable)과 전달(Call by ?) (개인 블로그)

 

반응형