목차
원시 타입 Primitive Type
C나 자바 같은 대표적인 프로그래밍 언어들은 기본적으로 원시 타입 제공
특히 C 언어: 동일한 정수형이라도 크기나 부호에 따라 매우 다양한 원시 타입을 제공.
파이썬
원시타입 제공 안함 하나로 숫자를 단일형으로 처리할 수 있어 언어를 매우 단순한 구조로 만들 수 있음
C
원시타입 제공함
정확히 그 대척점에 놓인 언어
단순히 수를 표현하기 위해 C는 그림과 같이 엄청나게 많은 자료형을 제공.
(특징) 메모리에 정확하게 타입 크기만큼의 공간을 할당하고 그 공간을 오로지 값으로 채워넣음
- 물리 메모리 Physical Memory: 배열이라면 여기에 자료형의 크기만큼 공간을 갖는 요소가 연속된 순서로 배치되는 형태가 됨
자바
원시 타입을 제공하며 매우 빠른 연산이 가능하다.
자바에서 정수형 원시 타입은 C와 문법이 동일하며 다음과 같이 선언한다. 클래스 객체 Object
- 자바에 지원
- 원시 타입에 대응됨
- 원시타입에 지원 불가한 문자로 변환, 16진수로 변환, 시프팅 Shifting 같은 비트 조작도 지원
- 다만 이를 위한 여러 가지 부가 정보가 추가되므로, 메모리 점유율이 늘어남, 계산 속도 또한 감소함.
// 클래스 객체
Integer a = new Integer(5);
// 원시타입
int a = 5;
각 언어별 자료형의 특징
언어 | 지원 타입 형태 |
---|---|
C | 원시타입 |
java | 원시타입, 객체 |
python | 객체 |
객체
파이썬은 모든 것이 객체
자료형에 대한 불변 여부
클래스 | 설명 | 불변 여부 |
---|---|---|
bool | 부울 | 불변 |
int | 정수 | 불변 |
float | 실수 | 불변 |
tuple | 튜플/ 리스트와 튜플의 차이는 불변여부이며 이외에는 거의 동일_ 불변이므로 생성시 설정값 변경 불가 | 불변 |
str | 문자 | 불변 |
list | 리스트 | 가변 |
set | 중복된 값을 갖지 않는 집합 자료형 | 가변 |
dict | 딕셔너리 | 가변 |
1) 불변 객체
파이썬은 모든 것이 객체.
tuple
한번 값을 담아두면 더 이상 값을 변경 불가
- 상수처럼 read-only 용도로 사용하거나 무엇보다 값이 변하지 않기 때문에 dict 의 키나 set 의 값으로도 사용 가능.
- list 는 언제든 값이 변할 수 있기 때문에 dict 의 키로 정하거나 set 의 값으로는 추가 불가
변수를 할당하는 작업은 해당 객체에 대해 참조를 한다는 의미
여기에는 예외가 없으며 심지어 문자와 숫자도 모두 객체다.
문자와 숫자는 불변 객체라는 차이만 있을 뿐.
[증명]
>>> 10
>>> a = 10
>>> b = a
>>> id(10), id(a), id(b)
(4393858752, 4393858752, 4393858752)
만약 모두 원시 타입이라면 각각의 값들은 각 메모리의 다른 영역에 위치할 것.
파이썬은 모든 것이 객체이므로, 메모리 상에 위치한 객체의 주소를 얻어오는 id() 함수를 실행한 결과 모두 동일
만약 10 이 11 이 된다면 a 변수와 b 변수 모두 값이 11 로 바뀜
그러나 그런 일은 일어나지 않음
숫자와 문자는 모두 불변 객체이기 때문
(정리) 값을 담고 있는 변수는 사실은 참조일 뿐
실제로 값을 갖고 있는 int, str 은 모두 불변 객체.
2) 가변 객체
list
int , str 과 달리 list는 값이 바꾸기 가능
다른 변수가 참조하고 있을 때, 그 변수의 값 또한 변경됨.
>>> a = [1, 2, 3, 4, 5]
>>> b = a
>>> b
[1, 2, 3, 4, 5]
>>> a[2] = 4
>>> a
[1, 2, 4, 4, 5]
>>> b
[1, 2, 4, 4, 5]
만약 b 가 int 나 str 을 참조하고 있다면 불변 객체 이기 때문에 절대 이런일 발생 불가
list 는 가변 객체이기 때문에 가능.
[C++ 참조와 비교]
여기서 한 가지 주의할 점은 C++의 참조(Reference) 방식 vs 파이썬의 참조 할당 방식.
// C++
int a = 10;
int &b = a;
b = 7;
std::cout << a << std::endl;
---------------------------
7
#python
>>> a = 10
>>> b = a
>>> id(a), id(b)
(4550522560, 4550522560)
>>> b = 7
>>> a, id(a), id(b)
(10, 4550522560, 4550522464)
(파이썬 코드 설명)
- b = a를 통해 a와 b는 동일한 메모리 주소를 가리키게 됐지만,
- b = 7로 b에 새로운 값을 할당하게 되면 더 이상 b 변수는 a 변수를 참조X.
- 이제 b 변수는 7이라는 새로운 객체를 참조
- 따라서 b는 다른 ID,, a 변수의 값은 기존 10 그대로 유지.
동일한 참조의 의미를 지니지만 이처럼 C++와 파이썬은 할당 방식에서 다른 차이를 보이므로 기존에 C++에 익숙한 개발자라면 주의가 필요하다.
파이썬의 비교 연산자 is와 ==
둘의 관계는 파이썬의 객체 구조와 관련이 깊음
is
id() 값을 비교하는 함수 None은 널(null)로서 값 자체가 정의되어 있지 않으므로 ==로 비교가 불가. -> is로만 비교가 가능하다
if a is None:
pass
==
값을 비교하는 연산자.
>>> a = [1, 2, 3]
>>> a == a
True
>>> a == list(a)
True
>>> a is a
True
>>> a is list(a)
False
(코드 설명)
값은 동일하지만 list()로 한 번 더 묶어주면, 별도의 객체로 복사가 되고 다른 ID를 갖게 된다. -> is는 False가 된다.
copy.deepcopy()로 복사한 결과 또한 값은 같지만 ID는 다름
>>> a = [1, 2, 3] >
>> a == copy.deepcopy(a)
True
>>> a is copy.deepcopy(a)
False
속도
파이썬의 객체 구조는 파이썬이 C나 자바 같은 다른 언어에 비해 느린 중요한 이유 중 하나임
속도 비교
단순히 정수형의 덧셈 연산을 하는 경우
- 원시 타입: 메모리에서 값을 꺼내 한번 연산하면 끝
- 파이썬: 파이썬의 객체는 값을 꺼내는 데만 해도 var->PyObject_HEAD 에서 타입코드를 찾는 등(CPython에서 PyObject 는 C의 구조체이고 여기서 타입 코드를 찾아서 대응되는 C의 자료형을 확인한다) 여러 단계의 부가 작업이 필요.
* 자바: 원시 타입이 아닌 객체로 계산하게 되면 훨씬 더 느려짐
넘파이 NumPy
파이썬의 과학 계산 모듈
빠른 속도로도 유명
넘파이는 C로 만든 모듈이며 내부적으로 리스트를 C의 원시 타입으로 처리하기 때문.
참고 자료구조, 자료형, 추상 자료형
자료구조(Data Structure)
데이터에 효율적으로 접근하고 조작하기 위한 데이터의 조직, 관리, 저장 구조
일반적으로 원시 자료형을 기반으로 하는 배열, 연결 리스트, 객체(Object)
자료형(Data Type)
컴파일러 또는 인터프리터에게 프로그래머가 데이터를 어떻게 사용하는지를 알려주는 일종의 데이터 속성(Attribute)
자료형은 자료구조에 비해 훨씬 더 구체적
특정 언어에서 자료형이라 함은 정수(Integer), 실수(Floating-Point Number), 문자열(String) 등 해당 언어에서 지원하는 원시 자료형(Primitive Data Type)까지 포함하는 모든 자료의 유형
자료형의 관점에서 보자면 여러 원시 자료형을 조합한 자료구조는 복합 자료형(Composite Data Type)이 된다.
추상 자료형(Abstract Data Type)
일반적으로 줄여서 ADT라 부르며 자료형에 대한 수학적 모델을 지칭.
ADT란 해당 유형의 자료에 대한 연산들을 명기한 것.
ADT는 행동만을 정의할 뿐 실제 구현 방법은 명시X
-> 이런 점에서 자료구조와는 다름.
객체 지향 프로그래밍(OOP)의 추상화(Abstraction)를 떠올리면 이해하기 쉬울 것.
추상화: 필수적인 속성만 보여주고, 불필요한 정보는 감추는 것
즉, 인터 페이스만 보여주고 실제 구현은 보여주지 않는다는 점에서 ADT는 OOP의 추상화와 비슷한 개념.