# Глава 8. Классификация типов данных, создание объектов
> Всегда начинайте со структуры данных.
Джон Кармак
Рассмотрим структуры данных, встроенные в интерпретатор. Если однажды вы встанете перед дилеммой, применить ли встроенный в язык тип или пользовательский класс, то помните: в недрах интерпретатора CPython все встроенные типы — это оптимизированные структуры на языке C. Как следствие, они выигрывают по эффективности у пользовательских классов.
## Какие бывают типы данных
В питоне есть три категории типов:
- **Встроенные типы.** Для их использования не требуются дополнительные манипуляции вроде подключения модулей. Эти типы вшиты в интерпретатор. Например, целочисленный тип `int`.
- **Библиотечные типы,** доступные после импорта стандартных модулей языка. Эти типы — неотъемлемая часть питона, но для их использования требуется подключение модуля через ключевое слово `import`. К таким типам например относится `socket`, реализованный в одноименном модуле.
- **Пользовательские типы:** это любые классы из third-party модулей, которые устанавливаются менеджером пакетов, а также самописные классы из вашего кода. Например, `array` в библиотеке `numpy` для математических расчетов.
Встроенные типы предусмотрены для:
- Числовых значений (numerics).
- Последовательностей (sequences).
- Множеств (sets).
- Отображений ключ-значение (mappings).
- Прочих абстракций вроде файлов и исключений.
С этим знанием мы разберем, на какие категории делятся встроенные типы.
## Изменяемые и не изменяемые типы {#block-mutable-immutable-types}
Самое важное, что нужно помнить про встроенные типы: они делятся на изменяемые (mutable) и неизменяемые (immutable). Любая сущность в питоне является объектом. Целое число — это объект, функция — это объект, исключение — объект... Любая переменная — это объект, то есть экземпляр конкретного класса.
Когда объект инстанцируется, интерпретатор присваивает ему тип и уникальное число — id объекта. Эта судьба уготована даже целым числам и булевым флагам. Так вот, какие-то объекты в питоне могут менять свое состояние после инстанцирования и поэтому называются изменяемыми. А какие-то — не могут.
**Неизменяемые** встроенные типы:
- `int` — целое число,
- `float` — число с плавающей точкой,
- `complex` — комплексное число,
- `bool` — логическое значение,
- `NoneType` — тип для единственного объекта-синглтона: неопределенного значения `None`,
- `str` — строка,
- `tuple` — кортеж,
- `range` — неизменяемая последовательность чисел,
- `frozenset` — неизменяемое множество,
- `bytes` — неизменяемая последовательность байтов.
**Изменяемые** встроенные типы:
- `list` — список,
- `set` — множество,
- `dict`— словарь.
- `bytearray` — изменяемая последовательность байтов.
- `memoryview` — «окно» на некую область в памяти, через которое ее можно читать и модифицировать. Тип `memoryview` умеет работать с двумя встроенными типами: `bytes` и `bytearray`.
Обратите внимание, `int` и `str` — неизменяемые! Так что же, над ними нельзя проводить операций вроде инкремента и конкатенации? Можно, но под капотом интерпретатора это будет означать замену одного объекта на другой объект этого же типа с новым id.
Чтобы это доказать, воспользуемся двумя встроенными функциями: `id()` и `type()`.
Функция `id()` возвращает идентификатор объекта:
```python {.example_for_playground}
lang = "ru"
print(id(lang))
```
Этот код выведет произвольное целое число — id строкового объекта `lang`. Разумеется, от запуска к запуску число будет меняться. Например, вывод этого кода может выглядеть так:
```python
139799602438576
```
`type()` возвращает название класса (типа) объекта:
```python {.example_for_playground}
is_connected = True
print(type(is_connected))
```
Результат вывода этого кода в консоль будет таким:
```python
<class 'bool'>
```
Проведите эксперимент. Заведите переменную `count`, равную 5. Выведете в консоль ее тип. На следующей строчке выведите ее id. Затем инкрементируйте переменную на 1. {.task_text}
Инкремент — это оператор `+= n`, где `n` — целое число. {.task_text}
После инкремента вновь выведите id переменной. Визуально убедитесь, что id переменной `count` до инкремента и после инкремента не совпадают. {.task_text}
```python {.task_source #python_chapter_0080_task_0010}
```
Для получения типа переменной воспользуйтесь функцией `type()`. Для получения id переменной воспользуйтесь функцией `id()`. Инкремент переменной выглядит так: `count += 1`. {.task_hint}
```python {.task_answer}
count = 5
print(type(count))
print(id(count))
count += 1
print(id(count))
```
Как видите, эксперимент подтвердил тот факт, что `int` — неизменяемый тип. После каждой модификации переменной она неявным образом заменяется на новую. Мы будем часто касаться изменяемости и неизменяемости встроенных типов, а пока перейдем к другой их классификации: на скаляры и коллекции.
## Скалярные типы и коллекции
Встроенные типы данных делятся на две категории:
- Скалярные (их еще называют простые, неделимые).
- Коллекции (составные, структурированные).
Все **скалярные типы** в питоне неизменяемые. К ним относятся:
- Числа.
- `int`. Целое число: -98, 0, 9361 и так далее.
- `float`. Число с плавающей точкой: 3, 1e-7, 45.03455, -e5.
- `complex`. Комплексное число: `-5.6 + 2j`.
- `bool`. Логическое значение (флаг): `True` и `False`.
- `NoneType`. Неопределенное значение переменной: `None`.
**Коллекции** представлены типами:
- [Строка:](/courses/python/chapters/python_chapter_0100/) `str`, последовательность Unicode символов.
- [Список:](/courses/python/chapters/python_chapter_0110/) `list`, по сути массив.
- [Кортеж:](/courses/python/chapters/python_chapter_0120/) `tuple`, его можно назвать неизменяемым списком.
- [Множество:](/courses/python/chapters/python_chapter_0140#block-sets) `set`, набор уникальных значений.
- [Неизменяемое множество:](/courses/python/chapters/python_chapter_0140#block-frozensets) `frozenset`.
- [Словарь:](/courses/python/chapters/python_chapter_0150/) `dict`, контейнер пар ключ-значение.
- [Диапазон:](/courses/python/chapters/python_chapter_0130/) `range`, неизменяемая последовательность чисел.
- Последовательности бинарных значений: `bytes`, `bytearray`, `memoryview`.
## Создание объектов
Объекты в питоне создаются двумя способами.
**Способ первый:** просто присвоить объекту какое-то значение. Интерпретатор при этом сам выведет и присвоит наиболее подходящий тип. Вот как это выглядит на примере объявления логической переменной:
```python
x = False
```
**Способ второй:** вызвать конструктор, имя которого совпадает с именем желаемого типа. Конструктор может инициализировать объект значением по умолчанию либо переданным в него значением, а также привести аргумент к требуемому типу.
Инициализация логической переменной значением по умолчанию:
```python
x = bool()
```
Приведение значения с плавающей точкой к логическому значению:
```python
x = bool(9.9)
```
Второй способ применяется для приведения строки к числу, превращения значения с плавающей точкой в целое и прочих преобразований между типами:
```python
x = int(3.14)
```
Корректно присвойте целочисленной переменной `max_val` значение, вызвав конструктор с аргументом-строкой "255". {.task_text}
```python {.task_source #python_chapter_0080_task_0020}
```
В конструктор `int()` требуется передать строку `"255"`. Возвращаемый конструктором объект требуется присвоить переменной `max_val`. {.task_hint}
```python {.task_answer}
max_val = int("255")
```
## Резюмируем
- Все типы данных в питоне относятся ко встроенным, библиотечным либо пользовательским.
- Встроенные типы делятся на скалярные и коллекции.
- Встроенные типы делятся на изменяемые и не изменяемые. Все скалярные типы — неизменяемые.
- Скалярные типы — это `int`, `float`, `complex`, `bool`, `NoneType`.
- Есть два способа создания объектов: через обычное присваивание (например, `a = 8`) и через вызов конструктора (например, `b = float(a)`).
Наша группа в telegram. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!