파이썬을 일주일쯤 다루어 보는 중이다. 파이썬에서 call-by-reference 에 대해서 좀 파다가, id 라는 명령을 알게 되었다. id로 이런저런 것들의 값을 찍어보며 테스트를 좀 하다가 깨달은 점인데, 변수를 다루는 법이 다른 언어와 좀 다르다.
보통 언어의 (고전적인) 변수가 메모리 주소의 앨리어스 지정이며 컴파일러에서 그렇게 처리한다면, 파이썬의 변수는 레이어를 두는 듯 했다. 값이 들어간 메모리 주소를 capsulate 하고, 그에 대한 앨리어스를 네임스페이스에서 쌍으로 저장하는 것 같았다. 예를 들면, a = 3 후 a = 5를 수행하면 보통 언어는 동일한 메모리 주소의 값을 변경하는데, 파이썬은 별도의 메모리 주소에 5를 넣은 후 객체로 싸고, 그 후 기존의 변수 이름이 지정하는 객체를 바꾼다.
이 부분이 파이썬의 장단점이 동시에 드러나는 부분인 것 같다. 파이썬 컴파일러를 만들기는 굉장히 어려울 것이다. 코드가 런타임에서 메모리를 잡는 과정에 대한 predictability가 엄청 떨어질 것이기 때문이다. 성능 문제도 당연히 발생할 것이다.
트위팅한 내용에 아침놀님이 설명을 해 주었는데, 위의 예가 실제로 돌아갈 때는 3, 5라는 int 객체를 생성(혹은 인터프리터가 미리 캐시한 것 이용)하여 a라는 변수가 그것을 가리키는 식으로 돌아간다. Java에서 primitive type 이 없는 셈이다. 일반적인 숫자, 문자열, 부울 등의 기본형 타입은 모두 immutable이다. 뭔가 operation을 가할 때 마다 새로운 객체를 만들어서 리턴하는 식으로 돌아간다는 설명이었다.
코드에 쓰는 모든 상수가 다 객체이며, 성능 문제를 개선하기 위해 CPython 구현에서 0,1,None,False,True와 같이 자주 사용되는 값들에 대한 캐시를 두고 있다고 한다. 내부적으로 클래스의 멤버 변수나 메소드 등을 dictionary 형태로 관리하는데, 이때 이름 문자열을 그대로 쓰면 성능이 떨어지기 때문에 intern이라는 내장 함수로 포인터 단위 비교를 하도록 하는 트릭도 있다고 한다.
설명을 들으며, 파이썬 식으로 끊임없이 캐스팅을 해야 하는 경우에는 실제로 CPU에 들어가는 opcode 에서의 성능 저하가 굉장하지 않을까 생각되었다. 64비트 머신에서는 덕좀 보는 언어가 되려나? 싶기는 한데, C2D 에서의 64비트 지원이 일종의 opcode 파이버링을 통해서 되는 식이니 그다지 차이는 없을 것 같기도 하다.
여기까지, 트위터 대화 일부를 정리한 글.