Deep Dive Python : Python의 객체와 변수의 개념
들어가며
면접 과정에서 파이썬과 관련된 질문을 많이 받았는데, 생각보다 내가 파이썬을 잘 모르고 있다는 사실이 상당히 충격으로 다가왔다. 그래서 기본서로 공부할 책과 좀 더 심화적인 스킬들을 공부할 책을 선정해서 파이썬을 깊게 팔 예정이다. 포스팅 시리즈는 Deep Dive 시리즈로 선정했으며 일반적인 파이썬 기초와는 거리가 있을 것이다. Deep Dive Python 시리즈는 다음과 같은 것들을 중점으로 공부할 것이다.
- Python의 기초 활용보다는 기초에서는 살~짝 벗어난 관점들
- Python의 메모리 단계까지의 관점
- Python을 더 잘 활용하는 방법
- Python의 효율적으로 활용하는 것
- CPython과 공식문서로 자세한 분석
이 글을 읽는 사람이 만약 Python을 처음으로 입문하는 사람이라면 별로 추천하지 않는다. 이 글은 많은 컴퓨터공학적 지식이 기반에 깔려있다고 생각하고 작성하는 글이기 때문이다. 물론 꾸역꾸역 읽으면 어디가서 아는 척하긴 좋겠지만… 딱히 초보자에겐 추천하지 않는다.
Deep Dive Python 첫번째 시리즈로 Python의 객체와 변수 개념에 대해 다룰 것이다.
Python의 객체
Python의 구현체
우선 Python은 무슨 언어로 구현되어 있을까? Python의 표준 구현체는 C언어로 구현되어 있다. 물론 C++이나 파이썬, Java로 구현된 구현체들도 있지만 표준 구현체는 CPython이고 python의 공식 레포지토리도 CPython으로 지원한다.
Python Object
출처 : 나무위키 - 파이썬
파이썬 공식문서에 들어가보면 모든 구현체들이 Python Object라는 객체로 구현된 것을 볼 수 있다. 이렇게 공식문서를 보면 알 수 있듯이 파이썬은 객체 지향으로 개발된 언어라는 것을 알 수 있다. 그래서 보통 Python 자체를 순수 객체지향 언어라고 부른다.
다만 파이썬은 객체 지향 언어라고 표현하는 것은 조심할 필요가 있다. 물론 파이썬이 객체 지향으로 개발된 언어인 것이므로 틀린 말은 아니지만 객체 지향은 프로그래밍 패러다임이기 때문에 사용자의 사용성에 따라 불리는 것이 달라질 수 있다. 파이썬은 절차 지향으로 프로그래밍을 배우기도 하고 상황에 따라서는 함수형 프로그래밍도 가능하다.
파이썬의 객체는 크게 가변형(Mutable) 과 불변형(Immutable) 로 구분한다.
- 가변형 : 리스트, 딕셔너리, 집합(set) 등…
- 불변형 : 숫자, 문자열, 튜플 등…
이런 특징 때문에 파이썬은 함수에 매개변수를 어떤 것을 전달하냐에 따라 처리가 달라진다. 불변 객체를 넘겨줄 경우 특수한 처리를 하지 않는다면 Call by Value로 처리하고, 가변 객체를 넘겨주면 Call by Reference로 처리한다. 파이썬 공식문서에서는 Call by Assignment (할당에 의한 호출) 와 Call by Object Reference (객체 참조에 의한 호출) 이라 한다.
함수에 대한 얘기는 나중에 자세히 파보도록하고 일단 이번 포스팅에서는 불변 객체 위주의 변수 할당을 알아보겠다.
Python의 변수
Python의 변수와 객체의 관계
파이썬이든, C++이든 자바든 많은 언어들은 =
연산자를 활용해서 변수를 선언한다. C++와 같은 언어는 메모리에 변수가 저장되는 방식으로 관리한다. 새로운 변수에 다른 선언된 변수를 할당하면 새로운 메모리에 동일한 객체가 복사되는 방식으로 저장된다. 그래서 만약 동일 메모리의 변수를 가리키고 싶다면 C++은 포인터(pointer) 를 사용한다.
여기서 파이썬이 간단해보이지만 꽤 복잡한 언어인 이유가 나타나는데, CPython의 객체 코드를 뜯어보면 많은 포인터들로 구성되어 있다는 것을 알 수 있다. 일단 간단하게 깔고 들어가면, 파이썬의 변수 대입(=
)은 새로운 메모리 할당이 아니라 객체에 대한 참조이다.
Python 객체의 기초 지식
여기서부터 조금 복잡해지는데, 우선 기본적으로 알고 가야하는 파이썬 지식 중 하나는 파이썬에서 -5 ~ 256까지의 수는 이미 만들어진 객체를 할당한다는 것이다. 이 범위 밖의 정수는 새로 객체를 할당한다. 특이한 점은 같은 257을 두번 할당하면 서로 다른 객체가 선언된다.
여기서 객체의 주소와 비슷한 격인 내용을 확인하려면 id(변수명)
을 사용하면 객체의 아이덴티티를 알 수 있다.
Python의 변수 선언
파이썬에서 리스트를 사용하다보면 아래와 같은 코드를 짜고 난감한 결과를 경험한 적이 있을 것이다.
1
2
3
4
a = [1, 2, 3, 4]
b = a
b[0] = 1
위 코드에서 a의 값은 변화가 될까? 라는 질문을 받으면, C++을 메인으로 사용한 사람의 경우 변하지 않는다고 말할 것이다. 하지만 파이썬은 변하게 된다. 이유는 위에서 언급했던 파이썬의 변수 할당 방식때문이다.
파이썬은 변수에 값을 복사하는 개념이 아니라 변수가 지시(point)하는 객체가 바뀌는 것이다. 가끔 그런 생각해본 적 없는가? “파이썬은 왜 자료형을 선언하는 방식으로 변수를 선언하지 않지?”
파이썬에서 변수의 역할을 생각해보면 자료형을 굳이 선언할 필요가 없다. 왜냐면 파이썬에서 변수는 그냥 지시하는 객체만 바꾸면 되기 때문이다. 우리가 C++이나 자바에서 자료형을 선언하는 이유는 자료형에 따라 메모리에 할당하는 공간의 크기를 결정하기 때문이다. 하지만 파이썬은 객체를 생성하고 변수는 객체를 지시만 하면 되므로 그럴 필요가 없는 것이다.
이런 특징과 위에서 언급한 -5 ~ 256까지는 이미 만들어진 객체를 사용한다는 것 때문에 신기한 결과가 나타난다. 같은 257인데, 다르다고 나올 수 있다.
동일성 판단 (is
)
Python에서는 동일성을 판단하는 연산자가 크게 2가지 종류가 있다. ==
와 is
연산자이다. 일반적으로 프로그래밍 언어는 불필요한 연산자와 기능을 굳이 만들지 않는다. 그렇다면 얼핏 보기에 비슷한 두 연산자가 왜 있을까? 그 이유는 당연하게도 역할이 다르기 때문이다.
자바스크립트를 써 본 사람이라면 ==
과 ===
의 차이점을 알 것이다. 위 두 연산자의 차이도 이것과 비슷하다.
==
은 단순히 객체 값의 동일성을 판정하고, is
는 객체 자체의 동일성을 판정한다.
아래의 코드의 출력결과는 어떻게 될까?
1
2
3
4
5
6
7
8
9
10
a = 3
b = 3
c = 257
d = 257
print(a == b)
print(a is b)
print(c == d)
print(c is d)
물론 눈치 빠른 사람들은 T
T
T
F
라는 것을 알 수 있다. 근데 왜…? 객체가 같지/다르지? 라는 생각이 들 수 있다. 이유는 -5 ~ 256은 이미 만들어진 객체를, 범위 밖의 숫자는 새로 객체를 할당한다. 이런 이유때문에 3은 같게, 257은 다르게 나온다.
del
변수를 제거하는 연산, 특히 dictionary나 리스트에서 제거할때, del
연산자를 사용하는 것을 본 사람들이 있을 것이다. 이름이 del
이라서 처음 배운 언어가 뭐냐에 따라 메모리 할당 제거를 하는 것이라 생각할 수 있으나 del
의 역할은 변수와 객체의 연결관계를 분리하는 것이다.
그렇다면 여기서 사용되지 않는 객체는 어떻게 관리될까?
파이썬은 몇 개의 변수가 객체를 참조하고 있는지 관리하는 변수인 ob_refcnt
가 있다. 참조 변수가 만약 0이 된다면 파이썬은 일정 시간 후에 메모리를 해제하는 코드를 동작시킨다.
1
2
3
4
5
6
7
8
9
10
11
12
13
static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
{
_Py_DECREF_STAT_INC();
_Py_RefTotal--;
if (--op->ob_refcnt != 0) {
if (op->ob_refcnt < 0) {
_Py_NegativeRefcount(filename, lineno, op);
}
}
else {
_Py_Dealloc(op);
}
}
이런 방식을 써서 파이썬은 메모리를 관리한다.
파이썬은 변수만 봐도 굉장히 깊게 공부할 요소들이 많다. 이 부분은 파이썬이 동작하는 과정에서 중요한 부분이다. 변수 컨트롤을 진행하는 요소나 서비스를 개발하는 과정에서 리소스 관리에서도 중요하게 작용한다.
이번에는 불변 객체 위주로 변수를 봤고 다음 포스팅은 가변 객체인 리스트, 딕셔너리, set의 구조와 동작에 대해서 다뤄볼 예정이다.
Comments powered by Disqus.