메모리 구조와 LGB 규칙
LGB란 Local, Global, Builtins을 의미한다. 파이썬에서의 우선 순위는 Local 변수, Global 변수, Builtins 순서이다. 그리고 하나의 프로그램을 실행하게 되면 RAM이라는 메모리 영역에 대해 Text Area, String Area를 할당 받는다.
- Text Area: 컴파일된 코드가 올라가는 영역이다.
- String Area: 문자열이 올라가는 영역이며 Read-Only이다.
- Static(global): 전역 변수나 Static 변수가 할당된다.
- Heap(free): new라는 연산자로 할당받게 된다. 파이썬에서는 new가 없기 때문에 참조 변수 또는 클래스 이름을 선언해주면 할당해주게 된다. 일반적으로 객체가 생성되는 부분이다.
- Stack: 함수 몸체 안에 선언된 변수(지역 변수)가 할당된다.
g = 10
def fn():
g = 100
print('fn g=', g)
fn()
print('g=', g)
예제 코드를 보면 함수 바깥에 선언된 변수를 global 변수라 하며 global 영역에 할당된다. 그리고 함수 fn() 안에 선언된 local 변수 g는 함수가 call 될 때 stack에 할당된다. fn()이 종료되면 local 변수 g는 자동으로 소멸되며 print로 출력하면 global 변수의 값인 10이 출력된다.
그리고 함수 내부의 g를 출력하였을 때는 local 변수 g의 값이 출력된다. 그 이유는 LGB 규칙에 의해서 Local이 우선적으로 고려되어 출력되기 때문이다.
g = 10
def fn():
global g
g = 100
fn()
print('g=', g)
만약 함수 내부에 global 키워드를 주게 된다면 함수 내부의 g를 global 변수로 만들어주기 때문에 함수 외부에 선언된 g의 값이 100으로 바뀐다. 따라서 출력 결과 역시 100으로 확인 가능하다.
def fn():
myList = [10, 20, 30]
fn()
print(myList)
위의 예제 코드에서는 myList가 참조한 객체를 출력 할 수가 없다. fn()를 선언하고 call하면 선언된 리스트 객체가 heap 영역에 생성되지만 참조 변수는 stack 영역에 생성된다. 따라서 함수 call이 끝나게 되면 stack에 선언된 myList가 소멸된다. 그리고 리스트 객체도 소멸된다. 그 이유는 myList 변수가 소멸됨으로써 리스트 객체의 참조 계수가 1에서 0로 바뀌게 되어 아무도 리스트 객체를 참조하지 않기 때문이다.
def fn():
myList = [10, 20, 30]
print(id(myList))
return myList
ret = fn()
print(id(ret))
print(ret)
앞선 예제와 달리 리스트 객체의 소멸을 막기 위해서는 위와 같이 return을 받아주면 된다. 위의 예제 코드에서 myList 참조 변수를 return하게 되면 메모리에서 CPU register의 return 값 저장소인 eax 영역에 객체 주소를 임시 저장하게 된다. 그리고 ret에 임시 저장한 객체 주소를 넘겨주게 된다.
이때 ret는 global 영역에 할당된 참조 변수이며 myList 참조 변수는 소멸된다. 하지만 여전히 임시 저장된 주소를 넘겨 받은 ret 참조 변수가 리스트 객체를 참조하기 때문에 참조 계수는 1을 유지하므로 생성된 리스트 객체가 소멸되지 않는다. 결국 ret를 출력하면 예제 코드처럼 리스트 객체가 출력됨을 확인 가능하다. 그리고 id 함수를 사용하여 myList 및 ret가 참조하고 있는 객체 주소가 동일함을 알 수 있다.
#빌트인 확인
print(dir(__builtins__))
위의 예제 코드를 통해 파이썬의 내장 SYMBOL을 확인할 수가 있다.
출력 결과에서 첫 글자가 대문자로 표기된 내용들은 예외처리와 관련된 클래스이다. 이렇게 파이썬에 기본된 내장된 builtins를 확인할 수 있다.
__(언더바언더바)로 되어 있는 것들은 python에서 기본적으로 제공하는 global 변수로 볼 수 있다.
소문자로 되어 있는 것들은 python의 내장 함수 및 class이다.
str = "abc"
def fn():
str = 'cde'
print(str)
fn()
print(str)
a = 10
a = str(a)
print(a)
위의 예제 코드에서 ‘not callable’의 이유는 무엇일까? 원래 str은 builtin되어 있는 symbol 명이다. str의 역할은 인자로 준 값을 string 객체로 얻어오는 것이다. 하지만 LGB 규칙에 의해 global이 우선이고 builtins은 우선순위가 가장 낮기 때문에 이미 global로 선언되어 있는 str 참조 변수로 인해 우선 순위가 낮은 builtins symbol인 str을 사용할 수가 없게 된다. 따라서 error가 발생한다.
파이썬을 프로그래밍할때는 builtins 되어있는 symbol을 global 또는 local로 선언하게 되면 각각 영역에 해당 symbol을 사용할 수 없으므로 명명규칙을 주의해야 한다.
'언어 > Python' 카테고리의 다른 글
[Python] Python(파이썬) 문자열을 처리하는 다양한 방법! (0) | 2020.04.07 |
---|---|
[Python] Python(파이썬) 함수 (3) - 일급 함수(first class function) (0) | 2020.04.06 |
[Python] Python(파이썬) 함수 (1) - 구조 및 특징 (0) | 2020.04.02 |
[Python] Python(파이썬) 반복문(for, while)/range/축약형 문법 (0) | 2020.04.01 |
[Python] Python(파이썬) shallow copy(얕은 복사) 그리고 deep copy(깊은 복사) (0) | 2020.03.31 |