C언어로 코딩을 처음 배운 필자는 항상 궁금한 것이 있었다.
C언어의 경우 function(int argument1, int* argument2) 와 같이 포인터를 명시적으로 해주어 function에서 수정이 일어날 경우 이 함수를 호출한 Caller의 변수들에 영향을 줄지 예상하기가 쉬웠다.
하지만 Python의 경우 어떤방식으로 진행되는지 헷갈렸다. 그래서 이 글을 써보게 되었다.
파이썬은 포인터가 없는 것일까?
(이 글은 https://realpython.com/pointers-in-python/ 를 일부 reference해서 쓰여진 글이다. 혹시 헷갈리는 부분들이나 더 알고 싶은 부분들이 있다면 이 글을 읽어보도록 하자!)
결론부터 이야기하면, "Don't really exist"이다. 차차 알아가 보도록 하자.
(참고로 이 글은 CPython 기반으로 작성되었다.)
<파이썬은 포인터가 왜 없는 것일까?>
사실 구체적인 이유는 모른다고 한다.
하지만 일단 포인터 notation이 존재한다면 어려운 점들이 있다. C언어 코딩을 하다보면 참조하면 안되는(not supposed to read) 메모리 영역을 참조하였다는 오류를 자주 접할 수 있다. 이러한 영역을 읽으려는 시도 자체가 굉장히 위험하다. 그래서 파이썬은 memory address에 대한 이러한 operation들을 user로부터 떼어 놓기로 하였다. 그래서 파이썬에는 포인터가 존재하지 않고, 포인터의 장점들을 활용 할 수 있도록 기능들을 제공해준다. (포인터라는 명시적인 이름 자체는 없지만 기능들은 제공한다고 표현하는 것이 정확할 것 같다.)
파이썬에서의 포인터 기능들을 이해하기 위해서는
1. Immutable vs mutable objects 2. Python variables/names |
이렇게 두가지에 대해 알아야한다.
<파이썬의 Objects>
파이썬의 모든 것들은 object이고, isinstance()를 활용하여 확인이 가능하다.
더불어 이러한 object들은 최소 3개의 데이터를 내장하고 있는데,
1. Reference count
2. Type
3. Value
를 가지고 있다. 여기에서 Reference count의 경우 Memory Management를 위해 필요한 것이라고 하는데 궁금한 사람들은 https://realpython.com/python-memory-management/ 를 읽어보면 될 듯 하다.
더불어 object, instance, class등의 차이점에 대해 궁금한 사람들은 인터넷에 검색하면 쉽게 쿠키를 굽는다거나, 붕어빵을 만드는 예시들이 나오니 확인하길 바란다.
<Immutable vs Mutable Objects>
Python의 object는 무조건 Immutable type, Mutable type 둘중 하나이다.
이 두 type은
1. Immutable objects can't be changed
2. Mutable objects can be changed
의 성질을 가진다.
하지만 여기서 의문점이 들 수 있다. 분명히 위의 표에 따르면, int는 immutable 하고, 바뀔 수 없는데(수정할 수 없는데)
위의 그림처럼 x는 int인데 바뀐다. 이게 무슨일일까? 하지만 자세히 살펴보면,
x에 1을 더하기만 했는데 내가 새로 받은 x는 기존에 x가 아니라 새로운 object를 받은 것임을 알 수 있다. 한마디로 immutable하기 때문에 기존의 x에 change가 일어난 것이 아니라 new object를 새로 받게 된 것이다.
하지만 list와 같이 mutable한 object들은 수정을 가해도 id가 바뀌지 않음을 알 수 있다.
<변수를 이해하자>
파이썬은 실제로는 variable(변수)가 없다고 한다.
이게 무슨말이냐 하는 분들이 있겠지만 variable은 존재하지 않고 name만 존재한다. 통상 우리가 파이썬 변수라고 부르는 모든 친구들이 사실은 name이었던 것이다. 아래에서 이와 관련한 이야기들을 살펴보도록 하자.
C언어에서의 변수는
int x = 10;
다음과 같이 선언한다. 이것이 실제로 실행되게 되면,
1. integer를 위한 memory 영역 할당 2. 해당 memory 영역에 10을 assign 3. x가 해당 memory영역을 가리기케 만듬 |
의 step을 거칩니다. 따라서 만약 이후에
x = 11;
을 하게 되면,
해당하는 메모리 location의 value를 11로 만드는 것이기에 파이썬으로 생각해보면 두 상황에서 x의 id는 같다. 한마디로 mutable하다.
만약 현재의 상황에서
int y = x;
를 실행하게 되면, 각각 다른 location에 11이라는 값을 가진 x, y가 있게 되는 것이다. 즉 y를 수정해도 x가 바뀌지 않고, x를 수정해도 y가 바뀌지 않는다.
<Python의 Name>
C에서의 변수를 살펴보았는데 파이썬은 변수가 없다. name만 존재한다. 그럼 variable(변수)와 name은 도대체 뭐가 다른 것일까?
x = 10
파이썬에서 이 과정은 다음과 같은 step을 통해 일어난다.
1. PyObject를 생성한다. 2. PyObject를 위한 typecode를 integer로 설정한다. 3. 10을 PyObject에 set한다. 4. x라는 name을 만든다. 5. x가 new PyObject를 가리키게 만든다. 6. PyObject의 refcount를 1증가시킨다. |
다음과 같은 상황이 되는 것이다. C언어와 다르게 10이라는 Value가 존재하는 메모리 블록을 가지게 되는 것을 알 수 있다. 그래서 x라는 Python name은 자체 메모리를 가지지 않음을 알 수 있다.
만약 이 상황에서
x = 11
을 하게되면,
다음과 같이 된다.
이때 기존의 value 10의 Reference count는 0이 되고 이는 garbage collector에 의해 제거된다.
다음으로
y = x
를 하게 되면,
다음과 같이 PyObject의 Reference count가 1 증가하고, y라는 name이 해당 PyObject를 가리키는 것을 알 수 있다.
실제로 y is x를 해보면 둘이 같은 것을 알 수 있다.
이러한 상황들을 종합적으로 보았을 때, 파이썬을 한마디로 요약하자면, 파이썬은 변수를 할당하는 것이 아니라 name들을 reference들에 binding 시키는 것이다.
<Intern Objects in Python>
자 위의 터미널을 보자.
test.py를 만들어서 x, y를 할당하고 x is y를 하면 True를 return 함을 알 수 있고,
Python3 interpreter를 직접 열어서 같은 명령어를 실행시키면 False를 return 하는 것을 알 수 있다.
이 부분은 포스트에선 다루지 않기로 하고, 궁금한 사람들은 링크를 들어가보길 추천한다.
https://realpython.com/pointers-in-python/#a-note-on-intern-objects-in-python
<Python 에서 포인터처럼 사용하기>
Mutable type들은 포인터와 유사하게 사용이 가능하다. 한마디로 caller가 호출한 callee함수가 list와 같은 mutable 자료형을 수정하게 되면, caller쪽에서 다시 list를 사용하려고 보면 값이 수정되어 있을 수 있다는 것이다.
예시는 아래와 같다.
def callee(list_object):
list_object.append("wooseok")
def caller():
list_obj = []
print(f'list_object_before : {list_obj}')
callee(list_obj)
print(f'list_object_after : {list_obj}')
caller()
다음을 실행시켜 보면
list_object_before : []
list_object_after : ['wooseok']
가 출력되는 모습을 볼 수 있다.
하지만 만약 immutable type으로 이 과정을 진행시켜보면,
def callee(int_object):
int_object += 1
def caller():
int_obj = 3
print(f'int_object_before : {int_obj}')
callee(int_obj)
print(f'int_obj_after : {int_obj}')
caller()
int_object_before : 3
int_obj_after : 3
가 출력 되는 것을 알 수 있다.
'공부 > Python' 카테고리의 다른 글
[python] Class 변수 탐구 (0) | 2022.06.13 |
---|