Python 07-a) - 전역변수와 지역변수
앞선 내용에 이어서 가변객체와 불변객체의 특징을 함수를 사용해보면서 살펴 보겠다.
파이썬에서 전역변수와 지역변수를 나누는 이유는 무엇일까?
바로 원하지 않는 변수의 변화가 일어날 확률을 줄이기 위해서이다.
a = 100 # 불변 객체(숫자형)
b = "전역변수" # 불변 객체(문자열)
c = [1,2,3] # 가변 객체(리스트)
d = {"1번키":"1번값","2번키":"2번값"} # 가변 객체(딕셔너리)
def print__text():
b = a*5 # 불변 객체 a를 입력값으로 이용 and 지역변수로서 b 사용
print(f"함수 내에서 b : {b}")
c[0] = 2 # 가변 객체 c의 [0]번 인덱스의 값 변경
d["1번키"] = "함수 내에서 값 변경"
print(f"함수 내에서 c : {c}")
print(f"함수 내에서 d : {d}")
print(f"함수 실행 전 a : {a} b : {b} c : {c} d: {d}")
print__text()
print(f"함수 실행 후 a : {a} b : {b} c : {c} d: {d}")
함수 실행 전 a : 100 b : 전역변수 c : [1, 2, 3] d: {'1번키': '1번값', '2번키': '2번값'}
함수 내에서 b : 500
함수 내에서 c : [2, 2, 3]
함수 내에서 d : {'1번키': '함수 내에서 값 변경', '2번키': '2번값'}
함수 실행 후 a : 100 b : 전역변수 c : [2, 2, 3] d: {'1번키': '함수 내에서 값 변경', '2번키': '2번값'}
함수의 결과를 살펴보면 전역변수로 불변 객체인 숫자형 변수 a와 문자형 변수b, 가변 객체인 리스트 c, 딕셔너리 d를 선언했다.
먼저 불변 객체를 먼저 살펴보자.
함수내에서 입력으로 전역변수 a,b를 사용해도 그 값을 사용하는데 문제는 없어 보인다.
하지만 함수 내에서 b라는 이름을 변수로 사용할 경우 함수 내의 지역변수로서 역할을 하며 b가 "전역변수"가 아닌 500을 참조하고 있는 것을 볼 수 있다. 이 경우에는 함수 내부에서 b가 새로 정의되기 때문에 함수 외부의 b가 다르며 함수 내부의 b는 500을 참조하고 함수 외부의 b는 "전역함수"를 여전히 참조하고 있는 상황이다.
함수의 호출이 끝나며 다시 결과를 확인해보면 함수 내부의 b는 함수가 종료되며 참조가 해제되고 전역변수로 선언된 b가 출력되는 것이다.
이번에는 가변 객체를 살펴보자.
전역 변수로 함수 밖에서 선언된 c,d는 함수 내에서 값의 변화가 이루어졌다. 그리고 함수 내부에서 그 값을 출력하면 변경된 값이 출력됨을 알 수 있다.
하지만 불변 객체와 다르게 함수가 종료된 이후에도 값이 변경되어 출력됨을 알 수 있는데, 이는 가변 객체의 경우 객체에 할당된 메모리의 크기가 상황에 따라 변할 수 있기 때문이다. 함수 내에서 값을 변경해 줄 때 c와 d가 참조하는 메모리에 가서 그 값을 더 추가하거나 변경하는 것이다. 그렇기 때문에 함수가 종료되었을 때 값이 변경된 것이다.
그렇다면 함수 내부에서 전역변수로 선언된 불변 객체를 참조하고 있는 변수를 입력과 변수로서 함께 사용한다면 어떤일이 벌어질까?
a = 100
def print_a():
a = a+1
print_a()
a
UnboundLocalError: local variable 'a' referenced before assignment
오류가 발생함을 알 수 있다.
이건 함수 내에서 전역변수 a를 참조하려고 해서 발생하는 오류이다. 함수가 실행되며 외부의 값이 의도치 않게 변경되는 상황을 방지하기 위해서 함수 내에서는 함수 밖에 있는 변수의 주소를 참조할 수 없게 설정되어 있다. 일반적으로는 그렇지만 필요한 경우에는 global keyword를 이용해서 전역 변수에 접근하면 오류가 해결된다.
이처럼 객체의 특징은 프로그램이 동작하는데 있어서 상당히 중요한 개념임을 알 수 있다.