- Введение в тему
- Что такое динамическая типизация
- Разница между атомарными и структурными типы данных
- Числовые типы
- Int целое число
- Float число с плавающей точкой
- Complex комплексное число
- Bool логический тип данных
- Последовательности
- Str строка
- List список
- Tuple кортеж
- Dict словарь
- Set множество
- Файл
- Range object a type of iterable
- None
- Работа с типами в Python
- Как проверить тип данных
- Как поменять тип данных
- Отличие type от isinstance
Введение в тему
Данные не однородны. Информация, записанная на естественном языке, к примеру, это предложение, сильно отличается от данных, состоящих из чисел. Слова можно склонять, а числа – умножать. Для того, чтобы удобнее было работать с такими разными данными, создатели языков программирования разделяют их на различные типы. Типы данных Python не исключение. О них мы и поговорим в этом уроке.
Что такое динамическая типизация
Python, как уже говорилось, является типизированным языком программирования. Естественно, у такого языка должен быть механизм определения типа данных. Если бы этого не было, возникали бы ситуации, когда логика программы будет нарушена, а код выполнится некорректно.
Этим механизмом является типизация.
В процессе её выполнения выполняется определение используемых. Типизация бывает статической и динамической. При статической проверка выполняется во время компиляции программы, а при динамической — непосредственно во время выполнения программного кода.
У Пайтона типизация динамическая. Благодаря этому одну и ту же переменную можно использовать много раз с данными разных типов, и она при этом будет каждый раз менять свой тип чтобы код исполнялся корректно:
example_variable = 'Eggs'
print(type(example_variable))
example_variable = 500
print(type(example_variable))
example_variable = {325: 'Foo'}
print(type(example_variable))
#Вывод:
<class 'str'>
<class 'int'>
<class 'dict'>
Но, увлекаться этим не стоит – для улучшения читаемости кода, в большинстве случаев, лучше ввести дополнительные переменные для данных с другими типами. Это полезно ещё и тем, что переменные с хорошо выбранными названиями являются альтернативой комментариям и объясняют, что за данные они хранят.
Существует давний спор между сторонниками разных языков о том, какая типизация лучше: статическая или динамическая. Так как у обоих подходов есть и минусы, и плюсы, то правильным ответом будет: лучше, та типизация, которая больше подходит под Ваши задачи. В среднем, программы, написанные на языках со статической типизацией, более надёжны, но разработка на языках с динамической типизацией происходит быстрее. Часто встречается комбинированный подход, когда на динамическом языке пишут прототип программы, а потом, критически важные места переписывают на статический язык.
В последнее время набирает популярность «смешанная типизация». Самым ярким примером этого подхода является язык Rust: статическая типизация при входе и выходе из блока кода, но динамическая внутри этого блока. В последних версиях Питон тоже делает шаг в эту сторону: появился такой инструмент, как аннотирование типов или type hinting, но это тема отдельной статьи.
К основным плюсам динамической типизации относятся:
- Создание гетерогенных коллекций. Благодаря тому, что в Python 3 типы данных определяются во время run time (выполнения программы), можно создавать наборы данных, состоящие их элементов различных типов. Делается это не сложно:
example_variable = ('Eggs', 500, {325: 'Foo'})
- Абстрагирование в алгоритмах. Благодаря тому, что тип данных определяется «на лету», можно создавать универсальные алгоритмы, которые будут работать с любыми данными.
- Длина кода. Если не описывать тип каждой переменной, код, конечно же получается короче и становится более высокоуровневым, читаемым.
- Простота изучения. Поскольку преобразование типов – отдельная сложная тема, а в этих языках вся работа с типами происходит без участия программиста, то, естественно, на динамических языках проще писать и их легче учить.
К основным минусам динамической типизации относятся:
- Ошибки. Ошибки типизации и логические ошибки на их основе – это главная проблема динамических языков. Суть в том, что получая данные не того типа, который предполагал программист, программа преобразует их и исполнится без ошибок. Результат, конечно, будет не верным. Вот здесь и начнётся ад дебаггинга.
- Оптимизация. Статически типизированные языки, как правило, более быстрые, так как им не нужно тратить вычислительные ресурсы на определение типа. Статические языки являются более низкоуровневыми и позволяют лучше контролировать происходящее.
Разница между атомарными и структурными типы данных
Все типы данных в Python можно разделить на атомарные и ссылочные.
Атомарные:
- числа;
- строки;
- булевые;
- None
Ссылочные:
- списки;
- множества;
- кортежи;
- словари;
- функции;
- классы;
Разница между этими типами в том, что атомарные объекты, при их присваивании переменным, передаются по значению, а ссылочные передаются по ссылке.
example_variable1 = 'Eggs'
example_variable2 = example_variable1
example_variable1 = 500
print(example_variable1)
print(example_variable2)
#Вывод:
500
Eggs
Из вывода видно, что переменной example_variable2 было передано значение, содержащееся в example_variable1, а не ссылка, указывающая на область памяти.
Для ссылочных типов это работает иначе:
example_variable1 = ['Eggs']
example_variable2 = example_variable1
example_variable1[0] = 500
print(example_variable1)
print(example_variable2)
#Вывод:
[500]
[500]
Поскольку списки – это структурные (ссылочные) объекты, то, после присваивания переменной example_variable1 переменной example_variable2 передалась ссылка на объект списка и, при печати, на экран были выведены две идентичные надписи.
В этом и заключается разница.
Числовые типы
Данные, представленные как числа, являются одними из наиболее важных в программировании. В Python для работы с такими данными создано несколько типов данных:
— целочисленный,
— вещественный,
— комплексный,
— логический.
Int целое число
Понять целые числа очень просто. Самое простое определение: целые числа — это числа без дробной части. Могут быть нулём, положительными или отрицательными.
example_variable1 = 500
example_variable2 = example_variable1 - 43
example_variable3 = 2+2
print(example_variable1, example_variable2, example_variable3)
#Вывод:
500 457 4
Если есть числа, то к ним применимы математические операции. Целочисленные данные используются для исчисления разных математических выражений. Также int используется для описания количественных характеристик объектов.
Float число с плавающей точкой
Действительные или вещественные числа (числа с плавающей точкой) созданы для измерения непрерывных величин. Языки программирования не способы реализовать иррациональные или бесконечные числа, поэтому всегда есть место приближению с определенной точностью, а значит, и некоторые неточности, из-за чего возможны следующие ситуации:
print(0.11 + 0.11 + 0.11)
print(0.1 + 0.1 + 0.1)
print(0.2 * 6)
print(0.3 * 3 == 0.9)
#Вывод:
0.33
0.30000000000000004
1.2000000000000002
False
Объявление float ничем не отличаются от int:
example_variable1 = 500.0
example_variable2 = example_variable1 - 43
example_variable3 = 2+0.2
print(example_variable1, example_variable2, example_variable3)
#Вывод:
500.0 457.0 2.2
Не забудьте, что разделителем является точка, а не запятая! Если использовать запятую, интерпретатор Питона решит. Что имеет дело с кортежем целых чисел:
example_variable1 = 500,0
example_variable2 = example_variable1 - 43
example_variable3 = 2+0,2
print(example_variable1, example_variable2, example_variable3)
#Вывод:
…
example_variable2 = example_variable1 - 43
TypeError: unsupported operand type(s) for -: 'tuple' and 'int'
Без этого типа, конечно же, не получится использовать сложную математику.
Complex комплексное число
Как действительные числа расширяют множество рациональных чисел, так и комплексные расширяют ряд вещественных. Яркой особенностью комплексного ряда является то, что можно извлечь корень из отрицательного числа.
В Python комплексные числа задаются с помощью функции complex():
# пример комплексного числа
example_variable1 = complex(500, 37)
print(example_variable1)
# вещественная часть
print(example_variable1.real)
# мнимая часть
print(example_variable1.imag)
Комплексные числа широко применяются в сложных математических вычислениях, но, в большинстве случаев, этот тип данных Вам не пригодится.
Bool логический тип данных
Это достаточно простой для понимания тип. У bool есть всего два значения:
- Истина/Да (True);
- Ложь/Нет (False).
True эквивалентен единице, а False – нулю. Именно поэтому мы отнесли данный тип данных к числовым. Этот тип данных является наиболее часто используемым в программировании, поскольку он участвует в сравнениях, ветвлениях и циклах.
Последовательности
По-другому последовательности называют наборами или коллекциями. И, действительно, последовательности являются коллекциями некоторых данных.
Str строка
Строки встречаются в программировании очень часто. Ваше имя, или URL сайта куда нужно зайти парсеру – это всё строки. Строки – это наборы символов, поэтому они относятся к последовательностям.
List список
Список – это очередной вид последовательностей. Стоит отметить, что коллекции в Python бывают изменяемыми (mutable) и неизменяемыми. Список, множество и словарь– изменяемые наборы, а строки и кортежи – нет. Список — это упорядоченная (индексированная) и изменяемая коллекция, которая состоит из объектов произвольных типов.
Само название списков говорит об их предназначении быть объектами для хранения наборов данных. Списки в Python – это массивы данных из других языков с максимальными возможностями.
example_variable1 = [500, 'Kira', (6, 5, 4), {'a': 1, 'b': 2, 'c': 3}]
example_variable2 = [i for i in range(9, 2, -3)]
print(example_variable1)
print(example_variable2)
# Вывод
[500, 'Kira', (6, 5, 4), {'a': 1, 'b': 2, 'c': 3}]
[9, 6, 3]
Tuple кортеж
Кортежи в языке Python по сути являются неизменяемыми списками.
Интерпретатор Питона производит работу с кортежами быстрее, чем со списками, а значит, везде, где это возможно, предпочтительнее использовать кортежи.
example_variable1 = (500, 'Kira', (6, 5, 4), {'a': 1, 'b': 2, 'c': 3})
example_variable2 = tuple(i for i in range(9, 2, -3))
print(example_variable1)
print(example_variable2)
# Вывод
(500, 'Kira', (6, 5, 4), {'a': 1, 'b': 2, 'c': 3})
(9, 6, 3)
Dict словарь
Словари представляют собой неупорядоченный набор пар ключ: значение. По сути, словарь в Пайтон похож на справочник, где каждая запись – это пара связанных значений, по одному из которых (уникальному ключу) можно получить второе (собственно, значение). Представьте справочную систему, где, введя номер квартиры, Вы получите фамилию жильца. Так и работают справочники в Python.
example_variable1 = {500:600, 'Kira':700, 10:(6, 5, 4)}
print(example_variable1)
# Вывод
{500: 600, 'Kira': 700, 10: (6, 5, 4)}
Set множество
Этот набор может состоять только из данных неизменяемого типа, при этом данные не упорядочены и уникальны. Данный тип повторяет математическую теорию множеств и, в некоторых ситуациях, оказывается очень полезным.
example_variable1 = set((500, 'Kira', (6, 5, 4)))
print(example_variable1)
# Вывод
{(6, 5, 4), 'Kira', 500}
Файл
Операции с файлами, хранящимися где-то на внешнем носителе, в Python реализованы в виде файлов-объектов. Эти объекты имеют базовый тип, но имеют очень характерную черту: нельзя создать экземпляр объекта-файла при помощи литералов.
Для начала работы с файлами необходимо использовать функцию open() и передать ей имя файла и строку, описывающую режим работы функции.
Действия с файлами могут быть различными, а, значит, разными могут быть и режимы работы с ними:
- r– выбирается по умолчанию, означает открытие файла для чтения;
- w– файл открывается для записи (если не существует, то создаётся новый);
- x– файл открывается для записи (если не существует, то генерируется исключение);
- a– режим записи, при котором информация добавляется в конец файла, а не затирает уже имеющуюся;
- b– открытие файла в двоичном режиме;
- t– ещё одно значение по умолчанию, означающее открытие файла в текстовом режиме;
- +– читаем и записываем.
Range object a type of iterable
Отличительная черта языка Python состоит в том, что здесь реализована встроенная функция range(), которая может создавать непрерывную последовательность целых чисел:
Она очень помогает при создании циклов for.
for i in range(10):
print(i, end=' ')
# Вывод
0 1 2 3 4 5 6 7 8 9
None
None – специальный объект внутри Питона. Он означает пустоту, всегда считается «Ложью. Помимо этого, None возвращается функциями, как объект по умолчанию. То есть, если Вы не укажете в конце функции return, Ваша функция вернёт управление основному потоку исполнения программы со значением None.
Стоит отметить, что None – это, так называемый, singletone. Это означает, что все значения None являются одним единственным объектом, а не множеством объектов с одинаковым типом.
Работа с типами в Python
Как проверить тип данных
Узнать тип данных объекта в Python очень просто. Для этого необходимо использовать функцию type().
example_variable1 = {500:600, 'Kira':700, 10:(6, 5, 4)}
print(type(example_variable1))
# Вывод:
<class 'dict'>
Как поменять тип данных
В богатом арсенале Питона есть встроенные функции для приведения типов – int(), list(), set(), tuple(), str(), bin().
Эти функции не изменяют значение, а возвращают новое изменённое:
example_variable1 = 500
example_variable2 = str(example_variable1) + '%'
print(example_variable1)
print(example_variable2)
#Вывод
500
500%
# int() - преобразует числовую строку в целое число
example_variable1 = '500'
example_variable2 = int(example_variable1)
print(example_variable2, type(example_variable2))
# list() - приведение итерируемого объекта к списку
example_variable1 = (11, 12)
example_variable2 = list(example_variable1)
print(example_variable2, type(example_variable2))
# set() - трансформация итерируемого объекта во множество
example_variable1 = ['1', 'Kira', '1', 'Rinat']
example_variable2 = set(example_variable1)
print(example_variable2, type(example_variable2))
# tuple() - трансформация итерируемого объекта в кортеж
example_variable1 = 'Kira'
example_variable2 = tuple(example_variable1)
print(example_variable2, type(example_variable2))
# str() - приведение к строковому типу
example_variable1 = {'Kira': 500}
example_variable2 = str(example_variable1)
print(example_variable2, type(example_variable2))
# bin() - преобразует десятичное число в двоичный формат
example_variable1 = 500
example_variable2 = bin(example_variable1)
print(example_variable2, type(example_variable2))
#Вывод
500 <class 'int'>
[11, 12] <class 'list'>
{'Rinat', '1', 'Kira'} <class 'set'>
('K', 'i', 'r', 'a') <class 'tuple'>
{'Kira': 500} <class 'str'>
0b111110100 <class 'str'>
Отличие type от isinstance
В отличие от type(), функция isinstance() проверяет, принадлежит ли объект к определенному классу или нет и возвращает булево True или False.
А ещё isinstance() умеет проверять принадлежность объекта хотя бы к одному типу из кортежа, переданного в качестве второго аргумента.
Важным отличием также является то, что isinstance() учитывает наследование классов. Функция воспринимает объект производного класса, как объект базового.