{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "# Типы и модель данных\n", "\n", " \n", "**С.В. Лемешевский** (email: `sergey.lemeshevsky@gmail.com`), Институт математики НАН Беларуси\n", "\n", "Date: **Mar 18, 2020**\n", "\n", "\n", "\n", "\n", "\n", "\n", "Здесь разберем как Python работает с переменными и определим, какие\n", "типы данных можно использовать в рамках этого языка. Подробно рассмотрим модель\n", "данных Python, а также механизмы создания и изменения значения\n", "переменных." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Кратко о типизации языков программирования\n", "
\n", "\n", "Если достаточно формально подходить к вопросу о типизации языка Python, то\n", "можно сказать, что он относится к языкам с неявной сильной динамической\n", "типизацией.\n", "\n", "Неявная типизация означает, что при объявлении переменной вам не нужно\n", "указывать её тип, при явной – это делать необходимо. В качестве примера языков с\n", "явной типизацией можно привести Java, C++ . Вот как будет выглядеть объявление\n", "целочисленной переменной в Java и Python.\n", "\n", "* Java:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " int a = 1 ;\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Python:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "a = 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "\n", "\n", "# Типы данных в Python\n", "\n", "\n", "В Python типы данных можно разделить на встроенные в интерпретатор (`built-in`) и\n", "не встроенные, которые можно использовать при импортировании соответствующих\n", "модулей.\n", "\n", "К основным встроенным типам относятся:\n", "1. `None` (неопределенное значение переменной)\n", "\n", "2. Логические переменные (`Boolean Type`)\n", "\n", "3. Числа (`Numeric Type`)\n", "\n", "a. `int` – целое число\n", "\n", "b. `float` – число с плавающей точкой\n", "\n", "c. `complex` – комплексное число\n", "\n", "\n", "4. Списки (`Sequence Type`)\n", "\n", "a. `list` – список\n", "\n", "b. `tuple` – кортеж\n", "\n", "c. `range` – диапазон\n", "\n", "\n", "4. Строки (`Text Sequence Type`)\n", "\n", "a. `str`\n", "\n", "\n", "2. Бинарные списки ( Binary Sequence Types )\n", "\n", "a. `bytes` – байты\n", "\n", "b. `bytearray` – массивы байт\n", "\n", "c. `memoryview` – специальные объекты для доступа к внутренним данным объекта через `protocol buffer`\n", "\n", "\n", "4. Множества (`Set Types`)\n", "\n", "a. `set` – множество\n", "\n", "b. `frozenset` – неизменяемое множество\n", "\n", "\n", "3. Словари (`Mapping Types`)\n", "\n", "a. `dict` – словарь\n", "\n", "\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Модель данных\n", "\n", "\n", "Рассмотрим как создаются объекты в памяти, их устройство, процесс объявления\n", "новых переменных и работу операции присваивания.\n", "\n", "Для того, чтобы объявить и сразу инициализировать переменную необходимо\n", "написать её имя, потом поставить знак равенства и значение, с которым эта\n", "переменная будет создана.\n", "\n", "Например строка:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "b = 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Объявляет переменную `b` и присваивает ей значение `5`.\n", "\n", "Целочисленное значение `5` в рамках языка Python по сути своей является\n", "*объектом*. Объект, в данном случае – это абстракция для представления данных,\n", "данные – это числа, списки, строки и т.п. При этом, под *данными* следует понимать как\n", "непосредственно сами объекты, так и отношения между ними (об этом чуть позже).\n", "Каждый объект имеет три атрибута – это *идентификатор*, *значение* и *тип*.\n", "\n", "*Идентификатор* – это уникальный признак объекта, позволяющий отличать объекты\n", "друг от друга, а *значение* – непосредственно информация, хранящаяся в памяти,\n", "которой управляет интерпретатор. \n", "\n", "При инициализации переменной, на уровне интерпретатора, происходит\n", "следующее:\n", "* создается целочисленный объект `5` (можно представить, что в этот момент создается ячейка и число `5` «кладется» в эту ячейку);\n", "\n", "* данный объект имеет некоторый идентификатор, значение: `5`, и тип: целое число;\n", "\n", "* посредством оператора `=` создается ссылка между переменной `b` и целочисленным объектом `5` (переменная `b` ссылается на объект `5`).\n", "\n", "> **Об именах переменных.**\n", ">\n", "> Допустимые имена переменных в языке Python – это последовательность\n", "> символов произвольной длины, содержащей «начальный символ»\n", "> и ноль или более «символов продолжения». Имя переменной должно\n", "> следовать определенным правилам и соглашениям. \n", "> \n", "> Первое правило касается начального символа и символов\n", "> продолжения. Начальным символом может быть любой символ, который в\n", "> кодировке Юникод рассматривается как принадлежащий диапазону\n", "> алфавитных символов ASCII (`a`, `b`, ..., `z`, `A`, `B`, ..., `Z`),\n", "> символ подчеркивания (`_`), а также символы большинства национальных\n", "> (не английских) алфавитов. Каждый символ продолжения может быть\n", "> любым символом из тех, что пригодны в качестве начального символа,\n", "> а также любым непробельным символом, включая символы, которые\n", "> в кодировке Юникод считаются цифрами, такие как (`0`, `1`, ...,\n", "> `9`), и символ Каталана `·`. Идентификаторы чувствительны к регистру,\n", "> поэтому `TAXRATE`, `Taxrate`, `TaxRate`, `taxRate` и `taxrate` – это\n", "> пять разных переменных. \n", "> \n", "> Имя переменной не должно совпадать с ключевыми словами интерпретатора\n", "> Python. Список ключевых слов можно получить непосредственно в программе, для\n", "> этого нужно подключить модуль `keyword` и воспользоваться командой\n", "> `keyword.kwlist`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "import keyword\n", "print(\"Python keywords: \" , keyword.kwlist)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> \n", "> Проверить является или нет идентификатор ключевым словом можно так:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "keyword.iskeyword( \"try\" )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ">" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "keyword.iskeyword( \"b\" )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **Об использовании символа подчеркивания в именах переменных.**\n", ">\n", "> Не должны использоваться имена, начинающиеся и заканчивающиеся двумя\n", "> символами подчеркивания (такие как `__lt__`). В языке \n", "> Python определено множество различных специальных методов и переменных\n", "> с такими именами (и в случае специальных методов мы можем заменять их,\n", "> то есть создать свои версии этих методов), но мы не должны вводить\n", "> новые имена такого рода.\n", "> \n", "> Символ подчеркивания сам по себе может использоваться в качестве\n", "> идентификатора; внутри интерактивной оболочки интерпретатора или\n", "> в командной оболочке Python в переменной с именем `_` сохраняется\n", "> результат последнего вычисленного выражения. Во время выполнения\n", "> обычной программы идентификатор `_` отсутствует, если мы явно не\n", "> определяем его в своем программном коде. Некоторые программисты \n", "> любят использовать `_` в качестве идентификатора переменной цикла\n", "> в циклах `for` ... `in`, когда не требуется обращаться к элементам, по\n", "> которым выполняются итерации. Например:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "for _ in (0, 1, 2, 3, 4, 5):\n", " print(\"Hello\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Для того, чтобы посмотреть на объект с каким идентификатором ссылается данная\n", "переменная, можно использовать функцию `id()`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "a = 4\n", "b = 5\n", "id (a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "id (b)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "a = b\n", "id (a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Как видно из примера, идентификатор – это некоторое целочисленное значение,\n", "посредством которого уникально адресуется объект. Изначально переменная a\n", "ссылается на объект `4` с идентификатором `1829984576`, переменная `b`\n", "– на объект с `id = 1829984592`. После выполнения операции\n", "присваивания `a = b`, переменная a стала ссылаться на тот же объект,\n", "что и `b`.\n", "\n", "\n", "\n", "\n", "\n", "\n", "Тип переменной можно определить с помощью функции `type()`. Пример\n", "использования приведен ниже." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "a = 10\n", "b = \"hello\"\n", "c = ( 1 , 2 )\n", "type (a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "type (b)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "type (c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Изменяемые и неизменяемые типы данных\n", "\n", "\n", "В Python существуют изменяемые и неизменяемые типы.\n", "\n", "К неизменяемым (`immutable`) типам относятся:\n", "* целые числа (`int`);\n", "\n", "* числа с плавающей точкой (`float`);\n", "\n", "* комплексные числа (`complex`);\n", "\n", "* логические переменные (`bool`);\n", "\n", "* кортежи (`tuple`);\n", "\n", "* строки (`str`);\n", "\n", "* неизменяемые множества (`frozen set`).\n", "\n", "К изменяемым ( mutable ) типам относятся\n", "* списки (`list`);\n", "\n", "* множества (`set`);\n", "\n", "* словари (`dict`).\n", "\n", "Как уже было сказано ранее, при создании переменной, вначале создается объект,\n", "который имеет уникальный идентификатор, тип и значение, после этого переменная\n", "может ссылаться на созданный объект.\n", "\n", "Неизменяемость типа данных означает, что созданный объект больше не\n", "изменяется. Например, если мы объявим переменную `k = 15`, то будет создан объект\n", "со значением `15`, типа `int` и идентификатором, который можно узнать с помощью\n", "функции `id()`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "k = 15\n", "id (k)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "type (k)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Объект с `id = 1672501744` будет иметь значение `15` и изменить его уже нельзя.\n", "Если тип данных изменяемый, то можно менять значение объекта.\n", "\n", "Например, создадим список `[1, 2]`, а потом заменим второй элемент на\n", "`3`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "a = [1 ,2]\n", "id (a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "a[1] = 3\n", "a" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "id(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Как видно, объект на который ссылается переменная `a`, был изменен. Это можно\n", "проиллюстрировать следующим рисунком.\n", "\n", "\n", "\n", "\n", "\n", "\n", "В рассмотренном случае, в качестве данных списка, выступают не объекты, а\n", "отношения между объектами. Т.е. в переменной a хранятся ссылки на объекты\n", "содержащие числа `1` и `3`, а не непосредственно сами эти числа.\n", "\n", "\n", "\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Целочисленные типы\n", "\n", "\n", "В языке Python имеется два целочисленных типа, `int` и `bool`. И целые\n", "числа, и логические значения являются неизменяемыми объектами,\n", "но благодаря присутствию в языке Python комбинированных операторов\n", "присваивания эта особенность практически незаметна. В логических\n", "выражениях число `0` и значение `False` представляют `False`, а любое\n", "другое целое число и значение `True` представляют `True`. В числовых \n", "выражениях значение `True` представляет `1`, а `False` – `0`. Это означает,\n", "что можно записывать весьма странные выражения, например, выражение `i\n", "+= True` увеличит значение `i` на единицу. Естественно, более\n", "правильным будет записывать подобные выражения как `i += 1`. \n", "\n", "Размер целого числа ограничивается только объемом памяти компьютера,\n", "поэтому легко можно создать и обрабатывать целое число, состоящее из\n", "тысяч цифр, правда, скорость работы с такими числами существенно\n", "медленнее, чем с числами, которые соответствуют машинному\n", "представлению.\n", "\n", "Литералы целых чисел по умолчанию записываются в десятичной сис-\n", "теме счисления, но при желании можно использовать другие системы\n", "счисления:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "14600926" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "0b110111101100101011011110" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "0o67545336" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "0xDECADE" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Двоичные числа записываются с префиксом `0b`, восьмеричные – в\n", "префиксом `0o` и шестнадцатеричные – с префиксом `0x`. В префиксах\n", "допускается использовать символы верхнего регистра.\n", "\n", "При работе с целыми числами могут использоваться обычные\n", "математические функции и операторы, как показано в\n", "табл. [1](#datatype:tbl:1). Для арифметических операций `+`, `-`, `/`,\n", "`//`, `%` и `**` имеются соответствующие комбинированные операторы\n", "присваивания: `+=`, `-=`, `/=`, `//=`, `%=` и `**=`, где выражение\n", "`x op= y` является эквивалентом выражения `x = x op y`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Таблица 1 : Арифметические операторы и функции\n", "\n", "\n", "\n", "| Синтаксис | Описание |
|---|---|
x + y | Складывает число x и число y |
x - y | Вычитает число y из числа x |
x * y | Умножает x на y |
x / y | Делит x на y – результатом всегда является значение типа float (или complex, если x или y является комплексным числом) |
x // y | Делит x на y, при этом усекает дробную часть, поэтому результатом всегда является значение типа int; смотрите также функцию round() |
x % y | Возвращает модуль (остаток) от деления x на y |
x**y | Возводит x в степень y; смотрите также функцию pow() |
-x | Изменяет знак числа x, если оно не является нулем, если ноль – ничего не происходит |
+x | Ничего не делает иногда используется для повышения удобочитаемости программного кода |
abs(x) | Возвращает абсолютное значение x |
divmod(x, y) | Возвращает частное и остаток деления x на y в виде кортежа двух значений типа int |
pow(x, y) | Возводит x в степень y; то же самое что и оператор ** |
pow(x, y, z) | Более быстрая альтернатива выражению (x ** y) % z |
round(x, n) | Возвращает значение типа int, соответствующее значению x типа float, округленному до ближайшего целого числа (или значение типа float, округленное до $n$-го знака после запятой, если задан аргумент n) |
| Синтаксис | Описание |
|---|---|
bin(i) | Возвращает двоичное представление целого числа i в виде строки, например, bin(1980) == '0b11110111100' |
hex(i) | Возвращает шестнадцатеричное представление целого числа i в виде строки, например, hex(1980) == '0x7bc' |
int(x) | Преобразует объект x в целое число; в случае ошибки во время преобразования возбуждает исключение ValueError, а если тип объекта x не поддерживает преобразование в целое число возбуждает исключение TypeError. Если x является числом с плавающей точкой, оно преобразуется в целое число путем усечения дробной части. |
int(s, base) | Преобразует строку s в целое число; в случае ошибки возбуждает исключение ValueError. Если задан необязательный аргумент base, он должен быть целым числом в диапазоне от 2 до 36 включительно. |
oct(i) | Возвращает восьмеричное представление целого числа i в виде строки, например, oct(1980) == '0o3674' |
| Синтаксис | Описание |
|---|---|
i | j | Битовая операция OR (ИЛИ) над целыми числами i и j; отрицательные числа представляются как двоичное дополнение |
i ^ j | Битовая операция XOR (исключающее ИЛИ) над целыми числами i и j |
i & j | Битовая операция AND (И) над целыми числами i и j |
i << j | Сдвигает значение i влево на j битов аналогично операции i * (2 ** j) без проверки на переполнение |
i >> j | Сдвигает значение i вправо на j битов аналогично операции i // (2 ** j) без проверки на переполнение |
\\~i | Инвертирует биты числа i |
| Синтаксис | Описание |
|---|---|
math.acos(x) | Возвращает арккосинус x в радианах |
math.acosh(x) | Возвращает гиперболический арккосинус x в радианах |
math.asin(x) | Возвращает арксинус x в радианах |
math.asinh(x) | Возвращает гиперболический арксинус x в радианах |
math.atan(x) | Возвращает арктангенс x в радианах |
math.atan2(y x) | Возвращает арктангенс y/x в радианах |
math.atanh(x) | Возвращает гиперболический арктангенс x в радианах |
math.ceil(x) | Возвращает $ | x | $, то есть наименьшее целое число типа int, большее и равное x, например, math.ceil(5.4) == 6 |
math.copysign(x y) | Возвращает x со знаком числа y |
math.cos(x) | Возвращает косинус x в радианах |
math.cosh(x) | Возвращает гиперболический косинус x в радианах |
math.degrees(r) | Преобразует число r типа float из радианов в градусы |
math.e | Константа $e$, примерно равная значению $2.7182818284590451$ |
math.exp(x) | Возвращает $e^x$, то есть math.e ** x |
math.fabs(x) | Возвращает $ | x | $, то есть абсолютное значение x в виде числа типа float |
math.factorial(x) | Возвращает $x!$ |
math.floor(x) | Возвращает $ | x | $, то есть наименьшее целое число типа int, меньшее и равное x, например, math.floor(5.4) == 5 |
math.fmod(x y) | Выполняет деление по модулю (возвращает остаток) числа x на число y; дает более точный результат, чем оператор %, применительно к числам типа float |
math.frexp(x) | Возвращает кортеж из двух элементов с мантиссой (в виде числа типа float) и экспонентой (в виде числа типа int) |
math.fsum(i) | Возвращает сумму значений в итерируемом объекте i в виде числа типа float |
math.hypot(x y) | Возвращает $\\sqrt{x^2 + y^2}$ |
math.isinf(x) | Возвращает True, если значение x типа float является бесконечностью ($\\pm \\infty$) |
math.isnan(x) | Возвращает True, если значение x типа float не является числом |
math.ldexp(m e) | Возвращает $m\\times 2^e$ – операция обратная math.frexp() |
math.log(x b) | Возвращает $\\log_b x$, аргумент b является необязательным и по умолчанию имеет значение math.e |
math.log10(x) | Возвращает $log_{10} x$ |
math.log1p(x) | Возвращает $log_e (1+x)$; дает точные значения даже когда значение x близко к 0 |
math.modf(x) | Возвращает дробную и целую часть числа x в виде двух значений типа float |
math.pi | Константа $\\pi$, примерно равная $3.1415926535897931$ |
math.pow(x y) | Возвращает $x^y$ в виде числа типа float |
math.radians(d) | Преобразует число d типа float из градусов в радианы |
math.sin(x) | Возвращает синус x в радианах |
math.sinh(x) | Возвращает гиперболический синус x в радианах |
math.sqrt(x) | Возвращает $\\sqrt{x}$ |
math.tan(x) | Возвращает тангенс x в радианах |
math.tanh(x) | Возвращает гиперболический тангенс x в радианах |
math.trunc(x) | Возвращает целую часть числа x в виде значения типа int; то же самое что и int(x) |
| Последовательность | Значение |
|---|---|
\\переводстроки | Экранирует (то есть игнорирует) символ перевода строки |
\\\\ | Символ обратного слеша (\\) |
\\' | Апостроф (') |
\\\" | Кавычка (\") |
\\a | Символ ASCII «сигнал» (bell, BEL) |
\\b | Символ ASCII «забой» (backspace, BS) |
\\f | Символ ASCII «перевод формата» (formfeed, FF) |
\\n | Символ ASCII «перевод строки» (linefeed, LF) |
\\N{название} | Символ Юникода с заданным названием |
\\ooo | Символ с заданным восьмеричным кодом |
\\r | Символ ASCII «возврат каретки» (carriage return, CR) |
\\t | Символ ASCII «табуляция» (tab, TAB) |
\\uhhhh | Символ Юникода с указанным 16-битовым шестнадцатеричным значением |
\\Uhhhhhhhh | Символ Юникода с указанным 32-битовым шестнадцатеричным значением |
\\v | Символ ASCII «вертикальная табуляция» (vertical tab, VT) |
\\xhh | Символ с указанным 8-битовым шестнадцатеричным значением |
| \"Country\" | \n", "2000 | \n", "2001 | \n", "2002 | \n", "2003 | \n", "2004 | \n", "
| \"Antigua and Barbuda\" | \n", "0 | \n", "0 | \n", "0 | \n", "0 | \n", "0 | \n", "
| \"Argentina\" | \n", "37 | \n", "35 | \n", "33 | \n", "36 | \n", "39 | \n", "
| \"Bahamas, The\" | \n", "1 | \n", "1 | \n", "1 | \n", "1 | \n", "1 | \n", "
| \"Bahrain\" | \n", "5 | \n", "6 | \n", "6 | \n", "6 | \n", "6 | \n", "