838

Python для начинающих: типы данных и как с ними работать

Python

Python — это высокоуровневый язык программирования с объектно-ориентированной парадигмой, основу которого составляют объекты и классы. Объект представляет собой выделенную область памяти, описанную классом (он же тип) и значением. Тип определяет область значений, которые может принимать объект, а также применимые к нему операции и методы.


Поскольку Python обладает огромным набором встроенных типов данных, в ходе решения стандартных задач питонистам приходится реже создавать собственные классы чем, к примеру, Java-разработчикам.


В этой статье рассмотрим, как работает строгая динамическая типизация в Python, какие бывают типы данных и как с ними работать на практике.

Строгая динамическая типизация в Python — что это?

Python является языком со строгой динамической типизацией. Приставка «строгая» означает, что Питон не выполняет неявные преобразования типов, благодаря чему не возникает неприятных «сюрпризов» при их смешивании.

 

 

Рассмотрим, что это значит на практике. Для этого запустим одинаковый код в Python и JavaScript:

// classic JavaScript sample
let someNumber = 1 + "1"
console. log('someNumber: ' + someNumber )
CONSOLE X
someNumber:11

JS просто объединит разные типы данных в одну строку и выдаст результат ‘11’, а Python сообщит об ошибке и выдаст такую ошибку:

>>> # No-no-nо!
...some_number = 1 + "1"
Traceback (most recent call last):
File "/usr/lib/python3.8/code.py", Line 90, in runcode
exec(code, self.locals)
File "<input>", line 2, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

На первый взгляд может показаться, что JavaScript поступил логичнее, да и вообще дает разработчикам больше свободы действий. Но на самом деле такое поведение может привести к непредсказуемым последствиям, особенно если говорить про большие скрипты на несколько тысяч строк кода. Например, было бы обидно если бы банковский сервис списал с карты не 50+50 = 100 долларов, а 5050 долларов.

В Python такая ситуация невозможна. Строгий интерпретатор мгновенно выдаст ошибку и не позволит программисту смешать типы данных.

Слово «динамическая» в названии говорит о том, что типы объектов определяются в ходе выполнения программы, то есть в режиме runtime. Следовательно, программисту  не нужно обязательно прописывать тип для каждой переменной. К слову, в языке Python переменные являются лишь указателями на объекты, и сами по себе не содержат информации о типе.

Создавать и изменять переменные можно когда угодно, главное требование — каждой из них должно быть присвоено значение.

Рассмотрим небольшой пример:

>>> # Let's try integer
... year_of_birth = 1999
>>> year_of_birth
1999
>>> # And now let's redefine year-of-birth - "ningggen ninety five"
>>> year_of_birth
'nineteen ninety five'

Для сравнения, в языках со статической типизацией, например таких как C++ или Java, типы объектов определяются на этапе компиляции. Следовательно, если вы захотите запустить этот код на Java, то столкнетесь с ошибкой:

int year of birth = 5;
System.out.println(year_of_birth);
//And now let's redefine
year_of_birth = "nineteen ninety five";
System.out.println(year_of_birth);

/home/user/IdeaProjects/BackEnd_Freel_Chat/src/main/java/Main.java:10:25
java: incompatible types: java. lang. String cannot be converted to int

И в конце концов, чтобы выполнить код вам придется создавать новую переменную:

int year_of_birth = 5;

System.out.println(year_of_birth);

// Let's create new variable str_year_of_birth

String str_year_of_birth = "nineteen ninety five";

System.out.println(str_year_of _birth);


/usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java ...
5
nineteen ninety five

Procces finished with exit code 0

При этом нельзя сказать что динамическая типизация лучше статической или наоборот. На практике у каждой из них есть свои плюсы и минусы.

Что такое изменяемые и неизменяемые типы данных

В языке Python все существующие типы данных можно разделить на изменяемые и неизменяемые. Рассмотрим, как это работает.

Присваивая новое значение не изменяемому объекту, Python его не перезаписывает, а создает новый объект с тем же именем. В итоге мы получаем два объекта с разными id и одинаковым названием. 

Проверим на практике:

>>> # Immutable data types
... number = 1
>>> # Check number id in memory
... id(number)
9445472
>>> # Redefine number
... number = 6
>>> # Check number id again. It changed
... id(number)
9445632

С другим id:

>>> # Immutable data types
... int_object = 10
>>> # Check number id in memory 
... id(int_object)
9445760
>>> # Let's change 1t 
... int_object += 5
>>> id(int_object)
9445920

В начале у нас есть переменная int_object со значением 10. Когда мы пытаемся прибавить к ней 5, создается новый объект с тем же именем. Обратите внимание, что у первого объекта id равняется #140271560307328, а у второго — #140271560307328.

А теперь рассмотрим, как в той же ситуации поведет себя список:

>>> # List is mutable
... list_object = [10, 20, 30]
>>> # Check list_object id in memory
id(list_object)
140271560307328
>>> # Let's change it
... list_object += [40]
>>> # And check id again
... id(List_object)
140271560367328

Как видим, идентификатор списка list_object остался таким же. Это связано с тем, что в Python списки являются изменяемыми объектами.

Подводя черту нужно отметить, что к неизменяемым объектам в языке Python относятся:

  • числа;
  • строки;
  • кортежи.

А к изменяемым:

  • списки;
  • словари;
  • множества.

Это свойство нужно обязательно учитывать при передаче объектов в функцию. К примеру, если вы не хотите допустить, чтобы функция изменила исходный список — передайте в нее его копию.

 

Встроенные типы данных в Python

Интерпретатор Python содержит множество типов данных. Их все можно разделить на три группы:

  • простые — числа и строки;
  • коллекции — списки, кортежи и словари;
  • остальные — файлы, итераторы, сокеты, NaN.

При написании кода рекомендуется отдавать предпочтение встроенным типам. Они являются оптимизированными структурами данных на языке С, благодаря чему более эффективны по сравнению с пользовательскими классами.

 

Числа в Python

Программное обеспечение на языке Python может работать несколькими типами числовых значений:

  • int — целые числа;
  • float — числа с плавающей точкой, они же десятичные дроби;
  • complex — комплексные числа.

В остальном числовые объекты в Python поддерживают такие же операции, как и другие языки программирования — сложение, умножение, деление:

>>> a = 20.5
... b = 10
...
... # Sum
... sum_a_b = a + b
>>> sum_a_b
30.5
>>> # MultipLication 
... mult_a_b = a + b
>>> mult_a_b
205.0
>>> # Division
... div_a_b = a / b
>>> div_a_b
2.05

Кроме того, стандартная библиотека Python содержит модуль math, подключаемый директивой import math. Он оснащен большим набором функций для работы с числовыми значениями:

>>> import math
>>> a = 20.5
>>> b = 10
>>> # factorial of b
... math_factor = math. factorial(b)
>>> math_factor
3628800
>>> # remainder of the division
... math_fmod = math. fmod(a, b)
>>> math_fod
0.5
>>> # cut off the fractional part
... math_trunc = math.trunc(a)
>>> math_trunc
20

Также стоит отдельно поговорить про специальный тип long в Python, который позволяет работать с числами неограниченной длины. Для сравнения в C++ самый большой тип long long ограничивается 64 битами, а значит самое большое положительное число здесь равняется 18 446 744 073 709 551 615. В Python такого предела нет. В качестве примера, попробуем получить какое-то очень большое число. 

Для этого возведем 27 в 560-ю степень:

>>> print (27 ** 569)
366191221537348906724224962113233696161029018222927370716739871087661400220838316

>>>

Строки в Python

Строки, тип string — это последовательности символов, к которым может применяться большинство методов других последовательностей: списков и кортежей.

Вот основные операции со строками, которые доступны в Python:

  • конкатенация строк — «склеивание» нескольких строк в одну;
  • длина строки — функция, подсчитывающая количество символов в строке и возвращающая соответствующее числовое значение;
  • извлечение элемента по индексу — функция, возвращающая значение элемента с нужным индексом — позицией символа внутри строки;
  • срез строки — извлечение из строки одного символа или целого фрагмента.

Кроме того, в Python строки поддерживают работу с отрицательными индексами, которые удобно использовать, чтобы обращаться к элементам в конце списка. Например, в выражении box_slice = some_string[-5:] мы вызываем пять последних символов строки some_string.

Также тип string обладает набором уникальных методов, которые актуальны только для него, например:

  • поиск подстроки;
  • поиск подстроки с заменой;
  • разделение строки по разделителю.

Списки в Python

Списки в языке Python представляют собой упорядоченные коллекции объектов. Они могут иметь неограниченное количество уровней вложенности и хранить любое количество объектов. Также один список может одновременно хранить объекты разных типов.

Над списками можно выполнять те же операции, что и со строками, однако в них есть и специфические методы, применимые только к ним, например:

  • добавление нового элемента в конец списка;
  • удаление элемента с нужным индексом;
  • сортировка элементов в нужном порядке — возрастания, убывания и прочее.

Кортежи в Python

Кортежи, или tuple — это такие же списки, только неизменяемые. Над ними можно проводить все те же операции, как и над списками, за исключением тех, что изменяют кортеж. 

Рассмотрим на практике:

>>> some_tuple = ('p', 'y', 't', 'h', 'o', 'n')
>>> # Get last element
... last_element = some_tuple[-1]
>>> last_element
'n'
>>> # slice from 0 to 3 index
... tuple_stice = some_tuple[0:3]
>>> tuple_slice 
('p', 'y', 't')
>>> # try to change first element 
... some_tuple[0] = 'c'

Если мы захотим изменить элемент ‘p’ на ‘c’, интерпретатор Python выдаст нам следующую ошибку:

>>> # try to change first element
... some_tuple [0] = 'c'
Traceback (most recent call last):
  File "/usr/lib/python3.8/code.py", line 90, in runcode 
    exec (code, self.locals)
  File "<input>", line 2, in <module>
TypeError: 'tuple' object does not support item assignment

На первый взгляд может показаться, что использовать кортежи вообще бессмысленно, ведь списки предоставляют гораздо больше методов. Однако, как мы уже говорили в примере с банковскими транзакциями, иногда разработчику нужно быть полностью уверенными, что функция не сможет изменить значение объекта ни при каких условиях, и в таких случаях кортежи просто незаменимы.

Словари в Python

Словарь, он же dict — это коллекция пар «ключ — значение». В качестве ключей здесь могут выступать абсолютно любые неизменяемые объекты: числа, строки и даже кортежи, а значениями могут быть объекты любых типов, включая другие словари.

Поскольку словари являются отображениями, а не последовательностями, располагаемые в них элементы не упорядочены. Следовательно, применяя к dict цикл for нужно понимать, что вывод элементов будет не всегда совпадать с порядком, который был задан при инициализации словаря.

 

Файлы в Python

Используя объекты-файлы в языке Python разработчик может взаимодействовать с файловой системой устройства. Для создания такого объекта используется функция open, в которую нужно передать имя файла и тип доступа — чтение или запись.

В качестве примера представим, что вы хотите написать книгу, посвященную Python. В таком случае, для начала нужно создать файл с типом доступа «запись» — w (write), а после — записывать в него строки текста, используя метод write().

Выглядеть это будет следующим образом:

>>> # Start from first chapter
... # Create book file in current folder
... my_book = open("my_book.txt", "w")
... my_book.write ("Chapter 1: Hello, Python\n")
... my_book.write("To be continued...\n")
... #Close the file 
... my_book.close()

Теперь, чтобы убедиться, что все прошло как надо, мы можем создать новый объект-файл, только в режиме чтения — r (read). Для этого пишем:

>>> Open our book and read content
... book = open("my_book.txt", "r")
... text = book.read()

Как видим, все строки которые мы записали раньше были записаны в файл.

Chapter 1: Hello, Python
To be continued ...

Где узнать больше о типах данных в Python

Описанных в этой статье знаний будет вполне достаточно для решения простейших задач. Чтобы углубиться в теорию и узнать системе типов всю актуальную информацию, рекомендуем изучить официальную документацию Python, раздел «Built-in Types».