{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- dom:TITLE: Типы и модель данных -->\n",
    "# Типы и модель данных\n",
    "<!-- dom:AUTHOR: С.В. Лемешевский Email:sergey.lemeshevsky@gmail.com at Институт математики НАН Беларуси -->\n",
    "<!-- Author: -->  \n",
    "**С.В. Лемешевский** (email: `sergey.lemeshevsky@gmail.com`), Институт математики НАН Беларуси\n",
    "\n",
    "Date: **Mar 4, 2020**\n",
    "\n",
    "<!-- Common Mako variable and functions -->\n",
    "<!-- -*- coding: utf-8 -*- -->\n",
    "\n",
    "\n",
    "\n",
    "Здесь разберем как Python работает с переменными и определим, какие\n",
    "типы данных можно использовать в рамках этого языка. Подробно рассмотрим модель\n",
    "данных Python, а также механизмы создания и изменения значения\n",
    "переменных.\n",
    "\n",
    "# Кратко о типизации языков программирования\n",
    "<div id=\"datatype:typization\"></div>\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": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "a = 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- Local Variables: -->\n",
    "<!-- doconce-chapter-nickname: \"chapter\" -->\n",
    "<!-- doconce-section-nickname: \"typization\" -->\n",
    "<!-- End: -->\n",
    "# Типы данных в Python\n",
    "<div id=\"datatype:types\"></div>\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",
    "<!-- Local Variables: -->\n",
    "<!-- doconce-chapter-nickname: \"datatype\" -->\n",
    "<!-- doconce-section-nickname: \"types\" -->\n",
    "<!-- End: -->\n",
    "\n",
    "\n",
    "## Модель данных\n",
    "<div id=\"datatype:model\"></div>\n",
    "\n",
    "Рассмотрим как создаются объекты в памяти, их устройство, процесс объявления\n",
    "новых переменных и работу операции присваивания.\n",
    "\n",
    "Для того, чтобы объявить и сразу инициализировать переменную необходимо\n",
    "написать её имя, потом поставить знак равенства и значение, с которым эта\n",
    "переменная будет создана.\n",
    "\n",
    "Например строка:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": 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": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import keyword\n",
    "print(\"Python keywords: \" , keyword.kwlist)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> \n",
    "> Проверить является или нет идентификатор ключевым словом можно так:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "keyword.iskeyword( \"try\" )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": 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": 6,
   "metadata": {
    "collapsed": 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": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "a = 4\n",
    "b = 5\n",
    "id (a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "id (b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": 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",
    "<!-- dom:FIGURE: [fig-datatype/refs.png, width=600 frac=1.0] -->\n",
    "<!-- begin figure -->\n",
    "![](fig-datatype/refs.png)<!-- end figure -->\n",
    "\n",
    "\n",
    "Тип переменной можно определить с помощью функции `type()`. Пример\n",
    "использования приведен ниже."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "a = 10\n",
    "b = \"hello\"\n",
    "c = ( 1 , 2 )\n",
    "type (a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "type (b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "type (c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- Local Variables: -->\n",
    "<!-- doconce-chapter-nickname: \"datatype\" -->\n",
    "<!-- doconce-section-nickname: \"model\" -->\n",
    "<!-- End: -->\n",
    "# Изменяемые и неизменяемые типы данных\n",
    "<div id=\"datatype:mutable\"></div>\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": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "k = 15\n",
    "id (k)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": 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": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "a = [1 ,2]\n",
    "id (a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "a[1] = 3\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "id(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Как видно, объект на который ссылается переменная `a`, был изменен. Это можно\n",
    "проиллюстрировать следующим рисунком.\n",
    "\n",
    "<!-- dom:FIGURE: [fig-datatype/mute.png, width=600 frac=1.0] -->\n",
    "<!-- begin figure -->\n",
    "![](fig-datatype/mute.png)<!-- end figure -->\n",
    "\n",
    "\n",
    "В рассмотренном случае, в качестве данных списка, выступают не объекты, а\n",
    "отношения между объектами. Т.е. в переменной a хранятся ссылки на объекты\n",
    "содержащие числа `1` и `3`, а не непосредственно сами эти числа.\n",
    "\n",
    "<!-- Local Variables: -->\n",
    "<!-- doconce-chapter-nickname: \"datatype\" -->\n",
    "<!-- doconce-section-nickname: \"mutable\" -->\n",
    "<!-- End: -->\n",
    "# Целочисленные типы\n",
    "<div id=\"datatype:decimal\"></div>\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": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "14600926"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "0b110111101100101011011110"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "0o67545336"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": 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`.\n",
    "\n",
    "\n",
    "## Таблица 1 : Арифметические операторы и функции\n",
    "<div id=\"datatype:tbl:1\"></div>\n",
    "\n",
    "\n",
    "<table border=\"1\">\n",
    "<thead>\n",
    "<tr><th align=\"left\">  Синтаксис   </th> <th align=\"left\">                                                                                                     Описание                                                                                                     </th> </tr>\n",
    "</thead>\n",
    "<tbody>\n",
    "<tr><td align=\"left\">   <code>x + y</code>           </td> <td align=\"left\">   Складывает число <code>x</code> и число <code>y</code>                                                                                                                                                                                      </td> </tr>\n",
    "<tr><td align=\"left\">   <code>x - y</code>           </td> <td align=\"left\">   Вычитает число <code>y</code> из числа <code>x</code>                                                                                                                                                                                       </td> </tr>\n",
    "<tr><td align=\"left\">   <code>x * y</code>           </td> <td align=\"left\">   Умножает <code>x</code> на <code>y</code>                                                                                                                                                                                                   </td> </tr>\n",
    "<tr><td align=\"left\">   <code>x / y</code>           </td> <td align=\"left\">   Делит <code>x</code> на <code>y</code> – результатом всегда является значение типа <code>float</code> (или <code>complex</code>, если <code>x</code> или <code>y</code> является комплексным числом)                                                                                    </td> </tr>\n",
    "<tr><td align=\"left\">   <code>x // y</code>          </td> <td align=\"left\">   Делит <code>x</code> на <code>y</code>, при этом усекает дробную часть, поэтому результатом всегда является значение типа <code>int</code>; смотрите также функцию <code>round()</code>                                                                           </td> </tr>\n",
    "<tr><td align=\"left\">   <code>x % y</code>           </td> <td align=\"left\">   Возвращает модуль (остаток) от деления <code>x</code> на <code>y</code>                                                                                                                                                                     </td> </tr>\n",
    "<tr><td align=\"left\">   <code>x**y</code>            </td> <td align=\"left\">   Возводит <code>x</code> в степень <code>y</code>; смотрите также функцию <code>pow()</code>                                                                                                                                                            </td> </tr>\n",
    "<tr><td align=\"left\">   <code>-x</code>              </td> <td align=\"left\">   Изменяет знак числа <code>x</code>, если оно не является нулем, если ноль – ничего не происходит                                                                                                                                 </td> </tr>\n",
    "<tr><td align=\"left\">   <code>+x</code>              </td> <td align=\"left\">   Ничего не делает иногда используется для повышения удобочитаемости программного кода                                                                                                                                  </td> </tr>\n",
    "<tr><td align=\"left\">   <code>abs(x)</code>          </td> <td align=\"left\">   Возвращает абсолютное значение <code>x</code>                                                                                                                                                                                    </td> </tr>\n",
    "<tr><td align=\"left\">   <code>divmod(x, y)</code>    </td> <td align=\"left\">   Возвращает частное и остаток деления <code>x</code> на <code>y</code> в виде кортежа двух значений типа <code>int</code>                                                                                                                               </td> </tr>\n",
    "<tr><td align=\"left\">   <code>pow(x, y)</code>       </td> <td align=\"left\">   Возводит <code>x</code> в степень <code>y</code>; то же самое что и оператор <code>**</code>                                                                                                                                                           </td> </tr>\n",
    "<tr><td align=\"left\">   <code>pow(x, y, z)</code>    </td> <td align=\"left\">   Более быстрая альтернатива выражению <code>(x ** y) % z</code>                                                                                                                                                                   </td> </tr>\n",
    "<tr><td align=\"left\">   <code>round(x, n)</code>     </td> <td align=\"left\">   Возвращает значение типа <code>int</code>, соответствующее значению <code>x</code> типа <code>float</code>, округленному до ближайшего целого числа (или значение типа <code>float</code>, округленное до $n$-го знака после запятой, если задан аргумент <code>n</code>)    </td> </tr>\n",
    "</tbody>\n",
    "</table>\n",
    "\n",
    "\n",
    "Объекты могут создаваться путем присваивания литералов переменным,\n",
    "например, `x = 17`, или обращением к имени соответствующего типа как к\n",
    "функции, например, `x = int(17)`. Создание объекта посредством\n",
    "использования его типа может быть выполнено одним из трех способов:\n",
    "\n",
    "* вызов типа данных без аргументов. В этом случае объект приобретает значение по умолчанию, например, выражение `x = int()` создаст целое число `0`. Любые встроенные типы могут вызываться без аргументов.\n",
    "\n",
    "* тип вызывается с единственным аргументом. Если указан аргумент соответствующего типа, будет создана поверхностная копия оригинального объекта. Если задан аргумент другого типа, будет предпринята попытка выполнить преобразование. Такой способ использования описывается в табл. [datatype:tbl:2](#datatype:tbl:2)\n",
    "\n",
    "* передается два или более аргументов; не все типы поддерживают такую возможность, а для тех типов, что поддерживают ее, типы аргументов и их назначение отличаются. В случае типа `int` допускается передавать два аргумента, где первый аргумент – это строка с представлением целого числа, а второй аргумент – число основания системы счисления. Например, вызов `int(\"A4\", 16)` создаст десятичное значение `164`.\n",
    "\n",
    "## Таблица 2 : Функции преобразования целых чисел <div id=\"datatype:tbl:2\"></div>\n",
    "\n",
    "\n",
    "<table border=\"1\">\n",
    "<thead>\n",
    "<tr><th align=\"left\">  Синтаксис   </th> <th align=\"left\">                                                                                                                                                              Описание                                                                                                                                                             </th> </tr>\n",
    "</thead>\n",
    "<tbody>\n",
    "<tr><td align=\"left\">   <code>bin(i)</code>          </td> <td align=\"left\">   Возвращает двоичное представление целого числа <code>i</code> в виде строки, например, <code>bin(1980) == '0b11110111100'</code>                                                                                                                                                                                                                             </td> </tr>\n",
    "<tr><td align=\"left\">   <code>hex(i)</code>          </td> <td align=\"left\">   Возвращает шестнадцатеричное представление целого числа <code>i</code> в виде строки, например, <code>hex(1980) == '0x7bc'</code>                                                                                                                                                                                                                            </td> </tr>\n",
    "<tr><td align=\"left\">   <code>int(x)</code>          </td> <td align=\"left\">   Преобразует объект <code>x</code> в целое число; в случае ошибки во время преобразования возбуждает исключение <code>ValueError</code>, а если тип объекта <code>x</code> не поддерживает преобразование в целое число возбуждает исключение <code>TypeError</code>. Если <code>x</code> является числом с плавающей точкой, оно преобразуется в целое число путем усечения дробной части.    </td> </tr>\n",
    "<tr><td align=\"left\">   <code>int(s, base)</code>    </td> <td align=\"left\">   Преобразует строку <code>s</code> в целое число; в случае ошибки возбуждает исключение <code>ValueError</code>. Если задан необязательный аргумент <code>base</code>, он должен быть целым числом в диапазоне от <code>2</code> до <code>36</code> включительно.                                                                                                                              </td> </tr>\n",
    "<tr><td align=\"left\">   <code>oct(i)</code>          </td> <td align=\"left\">   Возвращает восьмеричное представление целого числа <code>i</code> в виде строки, например, <code>oct(1980) == '0o3674'</code>                                                                                                                                                                                                                                </td> </tr>\n",
    "</tbody>\n",
    "</table>\n",
    "\n",
    "\n",
    "В табл. [datatype:tbl:3](#datatype:tbl:3) перечислены битовые операторы. Все битовые операторы\n",
    "(`|`, `^`, `&`, `<<` и `>>`) имеют соответствующие комбинированные операторы\n",
    "присваивания (`|=`, `^=`, `&=`, `<<=` и `>>=`), где выражение `i op= j` является\n",
    "логическим эквивалентом выражения `i = i op j` в случае, когда обращение\n",
    "к значению `i` не имеет побочных эффектов. \n",
    "\n",
    "\n",
    "## Таблица 3 : Функции преобразования целых чисел <div id=\"datatype:tbl:3\"></div>\n",
    "\n",
    "\n",
    "<table border=\"1\">\n",
    "<thead>\n",
    "<tr><th align=\"left\">Синтаксис</th> <th align=\"left\">                                                     Описание                                                     </th> </tr>\n",
    "</thead>\n",
    "<tbody>\n",
    "<tr><td align=\"left\">   <code>i | j</code>      </td> <td align=\"left\">   Битовая операция OR (ИЛИ) над целыми числами <code>i</code> и <code>j</code>; отрицательные числа представляются как двоичное дополнение    </td> </tr>\n",
    "<tr><td align=\"left\">   <code>i ^ j</code>      </td> <td align=\"left\">   Битовая операция XOR (исключающее ИЛИ) над целыми числами <code>i</code> и <code>j</code>                                                   </td> </tr>\n",
    "<tr><td align=\"left\">   <code>i & j</code>      </td> <td align=\"left\">   Битовая операция AND (И) над целыми числами <code>i</code> и <code>j</code>                                                                 </td> </tr>\n",
    "<tr><td align=\"left\">   <code>i << j</code>     </td> <td align=\"left\">   Сдвигает значение <code>i</code> влево на <code>j</code> битов аналогично операции <code>i * (2 ** j)</code> без проверки на переполнение              </td> </tr>\n",
    "<tr><td align=\"left\">   <code>i >> j</code>     </td> <td align=\"left\">   Сдвигает значение <code>i</code> вправо на <code>j</code> битов аналогично операции <code>i // (2 ** j)</code> без проверки на переполнение            </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\~i</code>        </td> <td align=\"left\">   Инвертирует биты числа <code>i</code>                                                                                            </td> </tr>\n",
    "</tbody>\n",
    "</table>\n",
    "\n",
    "\n",
    "## Логические значения\n",
    "<div id=\"datatype:decimal:bool\"></div>\n",
    "\n",
    "Существует два встроенных логических объекта: `True` и `False`. Как\n",
    "и все остальные типы данных в языке Python (встроенные, библиотечные\n",
    "или ваши собственные), тип данных `bool` может вызываться как \n",
    "функция – при вызове без аргументов возвращается значение `False`,\n",
    "при вызове с аргументом типа `bool` возвращается копия аргумента,\n",
    "а при вызове с любым другим аргументом предпринимается попытка\n",
    "преобразовать указанный объект в тип `bool`. Все встроенные типы\n",
    "данных и типы данных из стандартной библиотеки могут быть\n",
    "преобразованы в тип `bool`, а добавить поддержку такого преобразования в\n",
    "свои собственные типы данных не представляет никакой сложности. Ниже\n",
    "приводится пара присваиваний логических значений и пара логических\n",
    "выражений:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "t = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f = False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "t and f"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "t and True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "в языке Python имеется три логических оператора: `and`, `or` и\n",
    "`not`. Выражения с участием операторов `and` и `or` вычисляются в\n",
    "соответствии с логикой сокращенных вычислений (*short-circuit logic*),\n",
    "и возвращается операнд, определяющий значение всего\n",
    "выражения, тогда как результатом оператора `not` всегда\n",
    "является либо `True`, либо `False`.\n",
    "\n",
    "\n",
    "<!-- Local Variables: -->\n",
    "<!-- doconce-chapter-nickname: \"datatype\" -->\n",
    "<!-- doconce-section-nickname: \"decimal\" -->\n",
    "<!-- End: -->\n",
    "# Типы чисел с плавающей точкой\n",
    "<div id=\"datatype:float\"></div>\n",
    "\n",
    "Язык Python предоставляет три типа значений с плавающей точкой:\n",
    "встроенные типы `float` и `complex` и тип `decimal.Decimal` в\n",
    "стандартной библиотеке. Все три типа данных относятся к категории\n",
    "неизменяемых. Тип `float` представляет числа с плавающей точкой\n",
    "двойной точности, диапазон значений которых зависит от компилятора\n",
    "языка C (или C\\# или Java), применявшегося для компиляции интерпретатора\n",
    "Python. Числа этого типа имеют ограниченную точность и не могут\n",
    "надежно сравниваться на равенство значений. Числа типа `float`\n",
    "записываются с десятичной точкой или в экспоненциальной форме записи, \n",
    "например, `0.0`, `4.`, `5.7`, `-2.5`, `-2e9`, `8.9e-4`.\n",
    "\n",
    "В машинном представлении числа с плавающей точкой хранятся как\n",
    "двоичные числа. Это означает, что одни дробные значения могут быть\n",
    "представлены точно (такие как `0.5`), а другие – только приблизительно\n",
    "(такие как `0.1` и `0.2`). Кроме того, для представления используется\n",
    "фиксированное число битов, поэтому существует ограничение на\n",
    "количество цифр в представлении таких чисел. Ниже приводится\n",
    "поясняющий пример:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "0.0, 5.4, -2.5, 8.9e-4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Проблема потери точности – это не проблема, свойственная только\n",
    "языку Python; все языки программирования обнаруживают проблему\n",
    "с точным представлением чисел с плавающей точкой.\n",
    "\n",
    "Если действительно необходимо обеспечить высокую точность,\n",
    "можно использовать числа типа `decimal.Decimal`. Эти числа\n",
    "обеспечивают уровень точности, который вы укажете (по умолчанию 28\n",
    "знаков после запятой), и могут точно представлять периодические числа,\n",
    "такие как $0.1$ , но скорость работы с такими числами существенно\n",
    "ниже, чем с обычными числами типа `float`. Вследствие высокой точности\n",
    "числа типа `decimal.Decimal` прекрасно подходят для производства\n",
    "финансовых вычислений.\n",
    "\n",
    "Смешанная арифметика поддерживается таким образом, что результатом\n",
    "выражения с участием чисел типов `int` и `float` является число типа\n",
    "`float`, а с участием типов `float` и `complex` результатом является\n",
    "число типа `complex`. Поскольку числа типа `decimal.Decimal` имеют\n",
    "фиксированную точность, они могут участвовать в выражениях только с\n",
    "другими числами `decimal.Decimal` и с числами типа `int`; результатом \n",
    "таких выражений является число `decimal.Decimal`. В случае попытки\n",
    "выполнить операцию над несовместимыми типами возбуждается исключение\n",
    "`TypeError`.\n",
    "\n",
    "## Числа с плавающей точкой\n",
    "<div id=\"datatype:float:foat\"></div>\n",
    "\n",
    "Все числовые операторы и функции, представленные в\n",
    "табл. [Таблица 1 : Арифметические операторы и функции](#datatype:tbl:1), могут применяться к числам типа float,\n",
    "включая комбинированные операторы присваивания. Тип данных float может\n",
    "вызываться как функция – без аргументов возвращается число `0.0`, с\n",
    "аргументом типа float возвращается копия аргумента, а с аргументом\n",
    "любого другого типа предпринимается попытка выполнить преобразование\n",
    "указанного объекта в тип float. При преобразовании строки \n",
    "аргумент может содержать либо простую форму записи числа с десятичной\n",
    "точкой, либо экспоненциальное представление числа. При выполнении\n",
    "операций с числами типа float может возникнуть ситуация, \n",
    "когда в результате получается значение `NaN` (*not a number* – не\n",
    "число) или «бесконечность». К сожалению, поведение интерпретатора в\n",
    "таких ситуациях может отличаться в разных реализациях и зависит от \n",
    "математической библиотеки системы.\n",
    "\n",
    "Ниже приводится пример простой функции, выполняющей сравнение\n",
    "чисел типа float на равенство в пределах машинной точности:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def equal_float(a, b):\n",
    "    return abs(a - b) <= sys.float_info.epsilon"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Чтобы воспользоваться этой функцией, необходимо импортировать\n",
    "модуль `sys`. Объект `sys.float_info` имеет множество атрибутов. Так,\n",
    "`sys.float_info.epsilon` хранит минимально возможную разницу между\n",
    "двумя числами с плавающей точкой. На одной из 32-разрядных машин\n",
    "автора книги это число чуть больше $0.000 000 000 000 000 2$.\n",
    "Тип `float` в языке Python обеспечивает надежную точность до 17\n",
    "значащих цифр.\n",
    "\n",
    "В дополнение к встроенным функциональным возможностям работы\n",
    "с числами типа `float` модуль `math` предоставляет множество функций,\n",
    "которые приводятся в табл. [datatype:tbl:4](#datatype:tbl:4). Ниже приводятся\n",
    "несколько фрагментов программного кода, демонстрирующих, как можно\n",
    "использовать функциональные возможности модуля:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import math\n",
    "math.pi * (5 ** 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "math.hypot(5, 12)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "math.modf(13.732)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Модуль `math` в значительной степени опирается на математическую\n",
    "библиотеку, с которой был собран интерпретатор Python. Это означает,\n",
    "что при некоторых условиях и в граничных случаях функции модуля могут\n",
    "иметь различное поведение на различных платформах. \n",
    "\n",
    "\n",
    "## Таблица 4 : Функции и константы модуля `math` <div id=\"datatype:tbl:4\"></div>\n",
    "\n",
    "\n",
    "<table border=\"1\">\n",
    "<thead>\n",
    "<tr><th align=\"left\">     Синтаксис      </th> <th align=\"left\">                                                                          Описание                                                                         </th> </tr>\n",
    "</thead>\n",
    "<tbody>\n",
    "<tr><td align=\"left\">   <code>math.acos(x)</code>          </td> <td align=\"left\">   Возвращает арккосинус <code>x</code> в радианах                                                                                                                           </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.acosh(x)</code>         </td> <td align=\"left\">   Возвращает гиперболический арккосинус <code>x</code> в радианах                                                                                                           </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.asin(x)</code>          </td> <td align=\"left\">   Возвращает арксинус <code>x</code> в радианах                                                                                                                             </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.asinh(x)</code>         </td> <td align=\"left\">   Возвращает гиперболический арксинус <code>x</code> в радианах                                                                                                             </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.atan(x)</code>          </td> <td align=\"left\">   Возвращает арктангенс <code>x</code> в радианах                                                                                                                           </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.atan2(y x)</code>       </td> <td align=\"left\">   Возвращает арктангенс <code>y/x</code> в радианах                                                                                                                         </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.atanh(x)</code>         </td> <td align=\"left\">   Возвращает гиперболический арктангенс <code>x</code> в радианах                                                                                                           </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.ceil(x)</code>          </td> <td align=\"left\">   Возвращает $ | x | $,  то есть наименьшее целое число типа <code>int</code>, большее и равное <code>x</code>, например, <code>math.ceil(5.4) == 6</code>                                        </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.copysign(x y)</code>    </td> <td align=\"left\">   Возвращает <code>x</code> со знаком числа <code>y</code>                                                                                                                             </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.cos(x)</code>           </td> <td align=\"left\">   Возвращает косинус <code>x</code> в радианах                                                                                                                              </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.cosh(x)</code>          </td> <td align=\"left\">   Возвращает гиперболический косинус <code>x</code> в радианах                                                                                                              </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.degrees(r)</code>       </td> <td align=\"left\">   Преобразует число <code>r</code> типа <code>float</code> из радианов в градусы                                                                                                       </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.e</code>                </td> <td align=\"left\">   Константа $e$, примерно равная значению $2.7182818284590451$                                                                                                   </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.exp(x)</code>           </td> <td align=\"left\">   Возвращает $e^x$, то есть <code>math.e ** x</code>                                                                                                                        </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.fabs(x)</code>          </td> <td align=\"left\">   Возвращает $ | x | $, то есть абсолютное значение <code>x</code> в виде числа типа <code>float</code>                                                                                </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.factorial(x)</code>     </td> <td align=\"left\">   Возвращает $x!$                                                                                                                                                </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.floor(x)</code>         </td> <td align=\"left\">   Возвращает $ | x | $, то есть наименьшее целое число типа <code>int</code>, меньшее и равное <code>x</code>, например, <code>math.floor(5.4) == 5</code>                                        </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.fmod(x y)</code>        </td> <td align=\"left\">   Выполняет деление по модулю (возвращает остаток) числа <code>x</code> на число <code>y</code>; дает более точный результат, чем оператор <code>%</code>, применительно к числам типа <code>float</code>    </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.frexp(x)</code>         </td> <td align=\"left\">   Возвращает кортеж из двух элементов с мантиссой (в виде числа типа <code>float</code>) и экспонентой (в виде числа типа <code>int</code>)                                            </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.fsum(i)</code>          </td> <td align=\"left\">   Возвращает сумму значений в итерируемом объекте <code>i</code> в виде числа типа <code>float</code>                                                                                  </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.hypot(x y)</code>       </td> <td align=\"left\">   Возвращает $\\sqrt{x^2 + y^2}$                                                                                                                                  </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.isinf(x)</code>         </td> <td align=\"left\">   Возвращает <code>True</code>, если значение <code>x</code> типа <code>float</code> является бесконечностью ($\\pm \\infty$)                                                                       </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.isnan(x)</code>         </td> <td align=\"left\">   Возвращает <code>True</code>, если значение <code>x</code> типа <code>float</code> не является числом                                                                                           </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.ldexp(m e)</code>       </td> <td align=\"left\">   Возвращает $m\\times 2^e$ – операция обратная <code>math.frexp()</code>                                                                                                    </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.log(x b)</code>         </td> <td align=\"left\">   Возвращает $\\log_b x$, аргумент <code>b</code> является необязательным и по умолчанию имеет значение <code>math.e</code>                                                             </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.log10(x)</code>         </td> <td align=\"left\">   Возвращает $log_{10} x$                                                                                                                                        </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.log1p(x)</code>         </td> <td align=\"left\">   Возвращает $log_e (1+x)$; дает точные значения даже когда значение <code>x</code> близко к <code>0</code>                                                                            </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.modf(x)</code>          </td> <td align=\"left\">   Возвращает дробную и целую часть числа <code>x</code> в виде двух значений типа <code>float</code>                                                                                   </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.pi</code>               </td> <td align=\"left\">   Константа $\\pi$, примерно равная $3.1415926535897931$                                                                                                          </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.pow(x y)</code>         </td> <td align=\"left\">   Возвращает $x^y$ в виде числа типа <code>float</code>                                                                                                                     </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.radians(d)</code>       </td> <td align=\"left\">   Преобразует число <code>d</code> типа <code>float</code> из градусов в радианы                                                                                                       </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.sin(x)</code>           </td> <td align=\"left\">   Возвращает синус <code>x</code> в радианах                                                                                                                                </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.sinh(x)</code>          </td> <td align=\"left\">   Возвращает гиперболический синус <code>x</code> в радианах                                                                                                                </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.sqrt(x)</code>          </td> <td align=\"left\">   Возвращает $\\sqrt{x}$                                                                                                                                          </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.tan(x)</code>           </td> <td align=\"left\">   Возвращает тангенс <code>x</code> в радианах                                                                                                                              </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.tanh(x)</code>          </td> <td align=\"left\">   Возвращает гиперболический тангенс <code>x</code> в радианах                                                                                                              </td> </tr>\n",
    "<tr><td align=\"left\">   <code>math.trunc(x)</code>         </td> <td align=\"left\">   Возвращает целую часть числа <code>x</code> в виде значения типа <code>int</code>; то же самое что и <code>int(x)</code>                                                                        </td> </tr>\n",
    "</tbody>\n",
    "</table>\n",
    "\n",
    "\n",
    "## Комплексные числа\n",
    "<div id=\"datatype:float:complex\"></div>\n",
    "\n",
    "Тип данных `complex` относится к категории неизменяемых и хранит пару\n",
    "значений типа `float`, одно из которых представляет действительную\n",
    "часть комплексного числа, а другое – мнимую. Литералы комплексных\n",
    "чисел записываются как действительная и мнимая части, объединенные\n",
    "знаком `+` или `-`, а за мнимой частью числа следует символ `j`.\n",
    "Вот примеры нескольких комплексных чисел: `3.5+2j`, `0.5j`, `4+0j`,\n",
    "`-1 - 3.7j`. Обратите внимание, что если действительная часть числа\n",
    "равна `0`, ее можно вообще опустить.\n",
    "\n",
    "Отдельные части комплексного числа доступны в виде атрибутов `real`\n",
    "и `imag`. Например:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "z = -89.5+2.125j\n",
    "z.real, z.imag"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "За исключением `//`, `%`, `divmod()` и версии `pow()` с тремя\n",
    "аргументами все остальные арифметические операторы и функции,\n",
    "перечисленные в табл. [Таблица 1 : Арифметические операторы и функции](#datatype:tbl:1) могут использоваться для\n",
    "работы с комплексными числами, так же как и соответствующие\n",
    "комбинированные операторы присваивания. Кроме того, значения типа\n",
    "`complex` имеют метод `conjugate()`, который изменяет знак мнимой\n",
    "части. Например:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "z.conjugate()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "3-4j.conjugate()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Тип данных `complex` может вызываться как функция – без аргументов\n",
    "она вернет значение `0j`, с аргументом типа `complex` она вернет копию\n",
    "аргумента, а с аргументом любого другого типа она попытается\n",
    "преобразовать указанный объект в значение типа `complex`. При\n",
    "использовании для преобразования функция `complex()` принимает либо\n",
    "единственный строковый аргумент, либо одно или два значения типа\n",
    "`float`.\n",
    "\n",
    "Если ей передается единственное значение типа `float`, возвращается\n",
    "комплексное число с мнимой частью, равной `0j`.\n",
    "\n",
    "Функции в модуле `math` не работают с комплексными числами. Это\n",
    "сделано преднамеренно, чтобы гарантировать, что пользователи модуля \n",
    "`math` будут получать исключения вместо получения комплексных чисел в\n",
    "некоторых случаях.\n",
    "\n",
    "Если возникает необходимость использовать комплексные числа,\n",
    "можно воспользоваться модулем `cmath`, который содержит комплексные\n",
    "версии большинства тригонометрических и логарифмических функций,\n",
    "присутствующих в модуле math, плюс ряд функций, специально\n",
    "предназначенных для работы с комплексными числами, таких \n",
    "как `cmath.phase()`, `cmath.polar()` и `cmath.rect()`, а также\n",
    "константы `cmath.pi` и `cmath.e`, которые хранят те же самые значения\n",
    "типа `float`, что и родственные им константы в модуле `math`.\n",
    "\n",
    "## Числа типа `Decimal`\n",
    "<div id=\"datatype:float:decimal\"></div>\n",
    "\n",
    "Во многих приложениях недостаток точности, свойственный числам\n",
    "типа `float`, не имеет существенного значения, и эта неточность\n",
    "окупается скоростью вычислений. Но в некоторых случаях предпочтение \n",
    "отдается точности, даже в обмен на снижение скорости работы. Модуль\n",
    "`decimal` реализует неизменяемый числовой тип `Decimal`, который\n",
    "представляет числа с задаваемой точностью. Вычисления с участием \n",
    "таких чисел производятся значительно медленнее, чем в случае\n",
    "использования значений типа `float`, но насколько это важно, будет\n",
    "зависеть от приложения.\n",
    "\n",
    "Чтобы создать объект типа `Decimal`, необходимо импортировать модуль\n",
    "`decimal`. Например:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import decimal\n",
    "a = decimal.Decimal(9876)\n",
    "b = decimal.Decimal(\"54321.012345678987654321\")\n",
    "a + b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- Local Variables: -->\n",
    "<!-- doconce-chapter-nickname: \"datatype\" -->\n",
    "<!-- doconce-section-nickname: \"float\" -->\n",
    "<!-- End: -->\n",
    "# Строки\n",
    "<div id=\"datatype:strings\"></div>\n",
    "\n",
    "Строки в языке Python представлены неизменяемым типом данных `str`,\n",
    "который хранит последовательность символов Юникода. Тип данных `str`\n",
    "может вызываться как функция для создания строковых объектов – без\n",
    "аргументов возвращается пустая строка; с аргументом, который не\n",
    "является строкой, возвращается строковое представление аргумента; а в\n",
    "случае, когда аргумент является строкой, возвращается его\n",
    "копия. Функция `str()` может также использоваться как функция\n",
    "преобразования. В этом случае первый аргумент должен быть строкой или\n",
    "объектом, который можно преобразовать в строку, а, кроме того, функции\n",
    "может быть передано до двух необязательных строковых аргументов, один\n",
    "из которых определяет используемую кодировку, а второй определяет\n",
    "порядок обработки ошибок кодирования.\n",
    "\n",
    "Литералы строк создаются с использованием кавычек или апострофов, при\n",
    "этом важно, чтобы с обоих концов литерала использовались кавычки\n",
    "одного и того же типа. В дополнение к этому мы можем использовать\n",
    "строки в тройных кавычках, то есть строки, которые начинаются и\n",
    "заканчиваются тремя символами кавычки (либо тремя кавычками, либо\n",
    "тремя апострофами). Например:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "text = \"\"\"Строки в тройных кавычках могут включать 'апострофы' и \"кавычки\"\n",
    "без лишних формальностей. Мы можем даже экранировать символ перевода строки \\,\n",
    "благодаря чему данная конкретная строка будет занимать всего две строки.\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Если нам потребуется использовать кавычки в строке, это можно сделать\n",
    "без лишних формальностей – при условии, что они отличаются от кавычек,\n",
    "ограничивающих строку; в противном случае символы кавычек или\n",
    "апострофов внутри строки следует экранировать:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "a = \"Здесь 'апострофы' можно не экранировать, а \\\"кавычки\\\" придется.\"\n",
    "b = 'Здесь \\'апострофы\\' придется экранировать, а \"кавычки\" не обязательно.'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В языке Python символ перевода строки интерпретируется как завершающий\n",
    "символ инструкции, но не внутри круглых скобок (`()`), квадратных\n",
    "скобок (`[]`), фигурных скобок (`{}`) и строк в тройных кавычках. \n",
    "Символы перевода строки могут без лишних формальностей использоваться\n",
    "в строках в тройных кавычках, и мы можем включать символы перевода\n",
    "строки в любые строковые литералы с помощью экранированной\n",
    "последовательности `\\n`.\n",
    "\n",
    "Все экранированные последовательности, допустимые в языке Python,\n",
    "перечислены в табл. 2.6.\n",
    "\n",
    "\n",
    "## Таблица 5 : Функции и константы модуля `math` <div id=\"datatype:tbl:5\"></div>\n",
    "\n",
    "\n",
    "<table border=\"1\">\n",
    "<thead>\n",
    "<tr><th align=\"left\">Последовательность</th> <th align=\"left\">                             Значение                            </th> </tr>\n",
    "</thead>\n",
    "<tbody>\n",
    "<tr><td align=\"left\">   <code>\\переводстроки</code>      </td> <td align=\"left\">   Экранирует (то есть игнорирует) символ перевода строки               </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\\\</code>                  </td> <td align=\"left\">   Символ обратного слеша (<code>\\</code>)                                         </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\'</code>                  </td> <td align=\"left\">   Апостроф (<code>'</code>)                                                       </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\\"</code>                  </td> <td align=\"left\">   Кавычка (<code>\"</code>)                                                        </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\a</code>                  </td> <td align=\"left\">   Символ ASCII «сигнал» (bell, BEL)                                    </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\b</code>                  </td> <td align=\"left\">   Символ ASCII «забой» (backspace, BS)                                 </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\f</code>                  </td> <td align=\"left\">   Символ ASCII «перевод формата» (formfeed, FF)                        </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\n</code>                  </td> <td align=\"left\">   Символ ASCII «перевод строки» (linefeed, LF)                         </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\N{название}</code>        </td> <td align=\"left\">   Символ Юникода с заданным названием                                  </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\ooo</code>                </td> <td align=\"left\">   Символ с заданным восьмеричным кодом                                 </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\r</code>                  </td> <td align=\"left\">   Символ ASCII «возврат каретки» (carriage return, CR)                 </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\t</code>                  </td> <td align=\"left\">   Символ ASCII «табуляция» (tab, TAB)                                  </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\uhhhh</code>              </td> <td align=\"left\">   Символ Юникода с указанным 16-битовым шестнадцатеричным значением    </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\Uhhhhhhhh</code>          </td> <td align=\"left\">   Символ Юникода с указанным 32-битовым шестнадцатеричным значением    </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\v</code>                  </td> <td align=\"left\">   Символ ASCII «вертикальная табуляция» (vertical tab, VT)             </td> </tr>\n",
    "<tr><td align=\"left\">   <code>\\xhh</code>                </td> <td align=\"left\">   Символ с указанным 8-битовым шестнадцатеричным значением             </td> </tr>\n",
    "</tbody>\n",
    "</table>\n",
    "\n",
    "\n",
    "Если потребуется записать длинный строковый литерал, занимающий\n",
    "две или более строк, но без использования тройных кавычек, то можно\n",
    "использовать один из приемов, показанных ниже:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "t = \"Это не самый лучший способ объединения двух длинных строк, \" + \\\n",
    "    \"потому что он основан на использовании неуклюжего экранирования\"\n",
    "s = (\"Это отличный способ объединить две длинные строки, \"\n",
    "    \" потому что он основан на конкатенации строковых литералов.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Обратите внимание, что во втором случае для создания единственного\n",
    "выражения мы должны были использовать круглые скобки – без этих\n",
    "скобок переменной s была бы присвоена только первая строка, а наличие\n",
    "второй строки вызвало бы исключение `IndentationError`. \n",
    "\n",
    "## Сравнение строк\n",
    "<div id=\"datatype:strings:compare\"></div>\n",
    "\n",
    "Строки поддерживают обычные операторы сравнения `<`, `<=`, `==`, `!=`,\n",
    "`>` и `>=`. Эти операторы выполняют побайтовое сравнение строк в памяти.\n",
    "К сожалению, возникают две проблемы при сравнении, например,\n",
    "строк в отсортированных списках. Обе проблемы проявляются во всех\n",
    "языках программирования и не являются характерной особенностью\n",
    "Python.\n",
    "\n",
    "Первая проблема связана с тем, что символы Юникода могут быть\n",
    "представлены двумя и более последовательностями байтов.\n",
    "\n",
    "Вторая проблема заключается в том, что порядок сортировки некоторых\n",
    "символов зависит от конкретного языка.\n",
    "\n",
    "## Получение срезов строк\n",
    "<div id=\"datatype:strings:slices\"></div>\n",
    "\n",
    "Отдельные элементы последовательности, а, следовательно, и отдельные\n",
    "символы в строках, могут извлекаться с помощью оператора доступа к\n",
    "элементам (`[]`). В действительности этот оператор намного более\n",
    "универсальный и может использоваться для извлечения не только одного\n",
    "символа, но и целых комбинаций (подпоследовательностей) элементов или\n",
    "символов, когда этот оператор используется в контексте оператора\n",
    "извлечения среза.\n",
    "\n",
    "Для начала мы рассмотрим возможность извлечения отдельных\n",
    "символов. Нумерация позиций символов в строках начинается с 0 и\n",
    "продолжается до значений длины строки минус 1. Однако допускается\n",
    "использовать и отрицательные индексы – в этом случае отсчет начинается\n",
    "с последнего символа и ведется в обратном направлении к первому \n",
    "символу. На рис. [datatype:strings:fig:1](#datatype:strings:fig:1) показано, как нумеруются\n",
    "позиции символов в строке, если предположить, что было выполнено\n",
    "присваивание `s = \"Light ray\"`. \n",
    "\n",
    "<!-- dom:FIGURE: [fig-datatype/strings_1.png, width=600 frac=1.0] Номера позиций символов в строке <div id=\"datatype:strings:fig:1\"></div> -->\n",
    "<!-- begin figure -->\n",
    "<div id=\"datatype:strings:fig:1\"></div>\n",
    "![Номера позиций символов в строке](fig-datatype/strings_1.png)<!-- end figure -->\n",
    "\n",
    "\n",
    "Отрицательные индексы удивительно удобны, особенно индекс `-1`,\n",
    "который всегда соответствует последнему символу строки. Попытка\n",
    "обращения к индексу, находящемуся за пределами строки (или к любому\n",
    "индексу в пустой строке), будет вызывать исключение `IndexError`.\n",
    "Оператор получения среза имеет три формы записи:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```Python\n",
    "        seq[start]\n",
    "        seq[start:end]\n",
    "        seq[start:end:step]\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ссылка `seq` может представлять любую последовательность, такую как\n",
    "список, строку или кортеж. Значения `start`, `end` и `step` должны быть\n",
    "целыми числами (или переменными, хранящими целые числа). Первая форма\n",
    "— это запись оператора доступа к элементам: с ее помощью извлекается\n",
    "элемент последовательности с индексом `start`. Вторая форма записи\n",
    "извлекает подстроку, начиная с элемента с индексом `start` и заканчивая\n",
    "элементом с индексом `end`, *не включая* его.\n",
    "\n",
    "При использовании второй формы записи (с одним двоеточием) мы можем\n",
    "опустить любой из индексов. Если опустить начальный индекс, по\n",
    "умолчанию будет использоваться значение `0`. Если опустить конечный\n",
    "индекс, по умолчанию будет использоваться значение `len(seq)`. \n",
    "Это означает, что если опустить оба индекса, например, `s[:]`, это будет\n",
    "равносильно выражению `s[0:len(s)]`, и в результате будет извлечена,\n",
    "то есть скопирована, последовательность целиком.\n",
    "\n",
    "На рис. [datatype:strings:fig:2](#datatype:strings:fig:2) приводятся некоторые примеры\n",
    "извлечения срезов из строки `s`, которая получена в результате\n",
    "присваивания `s = \"The waxwork man\"`.\n",
    "\n",
    "<!-- dom:FIGURE: [fig-datatype/strings_2.png, width=600 frac=1.0] Извлечение срезов из последовательности <div id=\"datatype:strings:fig:2\"></div> -->\n",
    "<!-- begin figure -->\n",
    "<div id=\"datatype:strings:fig:2\"></div>\n",
    "![Извлечение срезов из последовательности](fig-datatype/strings_2.png)<!-- end figure -->\n",
    "\n",
    "\n",
    "Один из способов вставить подстроку в строку состоит в смешивании\n",
    "операторов извлечения среза и операторов конкатенации. Например:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "s = s[:12] + \"wo\" + s[12:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "s"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Кроме того, поскольку текст «wo» присутствует в оригинальной строке,\n",
    "тот же самый эффект можно было бы получить путем присваивания значения\n",
    "выражения `s[:12] + s[7:9] + s[12:]`.\n",
    "\n",
    "Оператор конкатенации `+` и добавления подстроки `+=` не\n",
    "особенно эффективны, когда в операции участвует множество строк. Для\n",
    "объединения большого числа строк обычно лучше использовать метод\n",
    "`str.join()`, с которым мы познакомимся в следующем подразделе.\n",
    "\n",
    "Третья форма записи (с двумя двоеточиями) напоминает вторую форму, но\n",
    "в отличие от нее значение `step` определяет, с каким шагом следует\n",
    "извлекать символы. Как и при использовании второй формы записи, мы\n",
    "можем опустить любой из индексов. Если опустить начальный \n",
    "индекс, по умолчанию будет использоваться значение `0`, при условии,\n",
    "что задано неотрицательное значение step; в противном случае начальный\n",
    "индекс по умолчанию получит значение `-1`. Если опустить конечный\n",
    "индекс, по умолчанию будет использоваться значение `len(seq)`, \n",
    "при условии, что задано неотрицательное значение step; в противном\n",
    "случае конечный индекс по умолчанию получит значение индекса перед\n",
    "началом строки. Мы не можем опустить значение step, и оно не может\n",
    "быть равно нулю – если задание шага не требуется, то следует\n",
    "использовать вторую форму записи (с одним двоеточием), в которой шаг \n",
    "выбора элементов не указывается.\n",
    "\n",
    "На рис. [datatype:strings:fig:3](#datatype:strings:fig:3) приводится пара примеров извлечения разреженных срезов из\n",
    "строки `s`, которая получена в результате присваивания\n",
    "`s = \"he ate camel food\"`.\n",
    "\n",
    "<!-- dom:FIGURE: [fig-datatype/strings_3.png, width=600 frac=1.0] Извлечение разреженных срезов <div id=\"datatype:strings:fig:3\"></div> -->\n",
    "<!-- begin figure -->\n",
    "<div id=\"datatype:strings:fig:3\"></div>\n",
    "![Извлечение разреженных срезов](fig-datatype/strings_3.png)<!-- end figure -->\n",
    "\n",
    "\n",
    "Здесь мы использовали значения по умолчанию для начального и ко-\n",
    "нечного индексов, то есть извлечение среза s[:: – 2] начинается с по-\n",
    "следнего символа строки и извлекается каждый второй символ по на-\n",
    "правлению к началу строки. Аналогично извлечение среза s[::3] на-\n",
    "чинается с первого символа строки и извлекается каждый третий сим-\n",
    "вол по направлению к концу строки.\n",
    "Существует возможность комбинировать индексы с размером шага,\n",
    "как показано на рис. [datatype:strings:fig:4](#datatype:strings:fig:4).\n",
    "\n",
    "<!-- dom:FIGURE: [fig-datatype/strings_4.png, width=800 frac=1.0] Извлечение срезов из последовательности с определенным шагом <div id=\"datatype:strings:fig:4\"></div> -->\n",
    "<!-- begin figure -->\n",
    "<div id=\"datatype:strings:fig:4\"></div>\n",
    "![Извлечение срезов из последовательности с определенным шагом](fig-datatype/strings_4.png)<!-- end figure -->\n",
    "\n",
    "\n",
    "Операция извлечения элементов с определенным шагом часто применяется к\n",
    "последовательностям, отличным от строк, но один из ее вариантов часто\n",
    "применяется к строкам:\n",
    "\n",
    "## Операторы и методы строк\n",
    "<div id=\"datatype:strings:operat\"></div>\n",
    "\n",
    "Поскольку строки относятся к категории неизменяемых\n",
    "последовательностей, все функциональные возможности, применимые к\n",
    "неизменяемым последовательностям, могут использоваться и со\n",
    "строками. Сюда входят оператор проверки на вхождение `in`, оператор\n",
    "конкатенации `+`,  оператор добавления в конец `+=`, оператор\n",
    "дублирования `*` и комбинированный оператор присваивания с\n",
    "дублированием `*=`. Применение всех этих операторов в контексте строк\n",
    "мы обсудим в этом подразделе, а также обсудим большинство строковых\n",
    "методов. В табл. 2.7 приводится перечень некоторых строковых методов.\n",
    "\n",
    "Так как строки являются последовательностями, они являются объектами,\n",
    "имеющими «размер», и поэтому мы можем вызывать функцию `len()`,\n",
    "передавая ей строки в качестве аргумента. Возвращаемая функцией длина\n",
    "представляет собой количество символов в строке (ноль – для пустых\n",
    "строк).\n",
    "\n",
    "Мы уже знаем, что перегруженная версия оператора `+` для строк\n",
    "выполняет операцию конкатенации. В случаях, когда требуется объединить\n",
    "множество строк, лучше использовать метод `str.join()`. Метод \n",
    "принимает в качестве аргумента последовательность (то есть список\n",
    "или кортеж строк) и объединяет их в единую строку, вставляя между\n",
    "ними строку, относительно которой был вызван метод. Например:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "treatises = [\"Arithmetica\", \"Conics\", \"Elements\"]\n",
    "\" \".join(treatises)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\"-<>-\".join(treatises)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\"\".join(treatises)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Метод `str.join()` может также использоваться в комбинации со\n",
    "встроенной функцией `reversed()`, которая переворачивает строку –\n",
    "например, `\"\".join(reversed(s))`, хотя тот же результат может быть\n",
    "получен более кратким оператором извлечения разреженного среза –\n",
    "например, `s[:: – 1]`.\n",
    "\n",
    "Оператор `*` обеспечивает возможность дублирования строки:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "s = \"=\" * 5\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "s *= 10\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Как показано в примере, мы можем также использовать комбинированный\n",
    "оператор присваивания с дублированием. \n",
    "\n",
    "## Форматирование строк с помощью метода `str.format()`\n",
    "<div id=\"datatype:strings:format\"></div>\n",
    "\n",
    "Метод `str.format()` представляет собой очень мощное и гибкое средство\n",
    "создания строк. Использование метода `str.format()` в простых случаях\n",
    "не вызывает сложностей, но для более сложного форматирования нам\n",
    "необходимо изучить синтаксис форматирования.\n",
    "\n",
    "Метод `str.format()` возвращает новую строку, замещая поля в\n",
    "контекстной строке соответствующими аргументами. Например:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\"The novel '{0}' was published in {1}\".format(\"Hard Times\", 1854)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Каждое замещаемое поле идентифицируется именем поля в фигурных\n",
    "скобках. Если в качестве имени поля используется целое число, оно\n",
    "определяет порядковый номер аргумента, переданного методу\n",
    "`str.format()`. Поэтому в данном случае поле с именем `0` было замещено\n",
    "первым аргументом, а поле с именем `1` – вторым аргументом. \n",
    "\n",
    "Если бы нам потребовалось включить фигурные скобки в строку формата,\n",
    "мы могли бы сделать это, дублируя их, как показано ниже:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\"{{{0}}} {1} ;-}}\".format(\"I'm in braces\", \"I'm not\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Если попытаться объединить строку и число, интерпретатор Python\n",
    "совершенно справедливо возбудит исключение `TypeError`. Но это легко\n",
    "можно сделать с помощью метода `str.format()`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\"{0}{1}\".format(\"The amount due is $\", 200)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "С помощью `str.format()` мы также легко можем объединять строки\n",
    "(хотя для этой цели лучше подходит метод `str.join()`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "x = \"three\"\n",
    "s =\"{0} {1} {2}\"\n",
    "s = s.format(\"The\", x, \"tops\")\n",
    "s"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В следующем разделе мы рассмотрим применение функции `str.format()`.\n",
    "\n",
    "<!-- Local Variables: -->\n",
    "<!-- doconce-chapter-nickname: \"datatype\" -->\n",
    "<!-- doconce-section-nickname: \"strings\" -->\n",
    "<!-- End: -->\n",
    "# Примеры\n",
    "<div id=\"datatype:examples\"></div>\n",
    "\n",
    "## Печать символов Юникода\n",
    "<div id=\"datatype:examples:print-unicode\"></div>\n",
    "\n",
    "Рассмотрим небольшой, но достаточно поучительный пример использования\n",
    "метода `str.format()`, в котором мы увидим применение спецификаторов\n",
    "формата в реальном контексте. Программа, состоящая всего из 25 строк\n",
    "выполняемого кода, находится в файле\n",
    "[print_unicode.py](src-datatype/print_unicode.py). Она импортирует\n",
    "два модуля, `sys` и `unicodedata` и определяет одну функцию –\n",
    "`print_unicode_table()`. Рассмотрение примера мы начнем\n",
    "с запуска программы, чтобы увидеть, что она делает; затем мы\n",
    "рассмотрим программный код в конце программы, где выполняется вся\n",
    "фактическая работа; и в заключение рассмотрим функцию, определяемую в\n",
    "программе."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%run src-datatype/print_unnicode.py Spoked"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "При запуске без аргументов программа выводит таблицу всех символов\n",
    "Юникода, начиная с пробела и до символа с наибольшим возможным\n",
    "кодом. При запуске с аргументом, как показано в примере, выводятся \n",
    "только те строки таблицы, где в названии символов Юникода содержится\n",
    "значение строки-аргумента, переведенной в нижний регистр.\n",
    "\n",
    "Разберем исходный код программы:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Start main script\n",
    "word = None\n",
    "\n",
    "if len(sys.argv) > 1:\n",
    "    if sys.argv[1] in (\"-h\", \"--help\"):\n",
    "        print(\"usage: {0} [string]\".format(sys.argv[0]))\n",
    "        word = 0\n",
    "    else:\n",
    "        word = sys.argv[1].lower()\n",
    "\n",
    "if word != 0:\n",
    "    print_unicode_table(word)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "После инструкций импортирования и определения функции\n",
    "`print_unicode_table()` выполнение достигает программного кода,\n",
    "показанного выше. Сначала предположим, что пользователь не указал в\n",
    "командной строке искомое слово. Если аргумент командной строки\n",
    "присутствует и это `-h` или `--help`, программа выводит информацию о\n",
    "порядке использования и устанавливает флаг `word` в значение `0`, указывая\n",
    "тем самым, что работа завершена. В противном случае в переменную `word`\n",
    "записывается копия аргумента, введенного пользователем, с\n",
    "преобразованием всех символов в нижний регистр. Если значение `word` не\n",
    "равно `0`, программа выводит таблицу.\n",
    "\n",
    "При выводе информации о порядке использования применяется спецификатор\n",
    "формата, который представляет собой простое имя формата, в данном\n",
    "случае – порядковый номер позиционного аргумента. Мы могли бы записать\n",
    "эту строку, как показано ниже:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(\"usage: {0[0]} [string]\".format(sys.argv))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "При таком подходе первый символ `0` соответствует порядковому номеру\n",
    "позиционного аргумента, а `[0]` — это индекс элемента внутри\n",
    "аргумента, и такой прием сработает, потому что `sys.argv` является\n",
    "списком."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def print_unicode_table(word):\n",
    "    print(\"decimal hex chr {0:^40}\".format(\"name\"))\n",
    "    print(\"------- ----- --- {0:-<40}\".format(\"\"))\n",
    "\n",
    "    code = ord(\" \")\n",
    "    end = sys.maxunicode\n",
    "\n",
    "    while code < end:\n",
    "        c = chr(code)\n",
    "        name = unicodedata.name(c, \"*** unknown ***\")\n",
    "        if word is None or word in name.lower():\n",
    "            print(\"{0:7} {0:5X} {0:^3c} {1}\".format(code, name.title()))\n",
    "        code += 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Первый вызов `str.format()` выводит текст `\"name\"`, отцентрированный в\n",
    "поле вывода, шириной 40 символов, а второй вызов выводит пустую строку\n",
    "в поле шириной 40 символов, используя символ `-` в качестве\n",
    "символа-заполнителя, с выравниванием по левому краю. \n",
    "\n",
    "Как вариант, вторую строку функции можно было записать, как показано ниже:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(\"------- ----- --- {0}\".format(\"-\" * 40))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Здесь мы использовали оператор дублирования строки (`*`), чтобы\n",
    "создать необходимую строку, и просто вставили ее в строку формата.\n",
    "\n",
    "Текущий код символа Юникода сохраняется в переменной `code`, которая\n",
    "инициализируется кодом пробела (`0x20`). В переменную end записывается\n",
    "максимально возможный код символа Юникода, который может принимать\n",
    "разные значения в зависимости от того, какая из кодировок\n",
    "использовалась при компиляции Python.\n",
    "\n",
    "Внутри цикла `while` с помощью функции `chr()` мы получаем символ\n",
    "Юникода, соответствующий числовому коду. Функция `unicodedata.name()`\n",
    "возвращает название заданного символа Юникода, во втором\n",
    "необязательном аргументе передается имя, которое будет использовано в\n",
    "случае, когда имя символа не определено. \n",
    "\n",
    "Если пользователь не указывает аргумент командной строки (`word is None`)\n",
    "или аргумент был указан и он входит в состав копии имени символа\n",
    "Юникода, в которой все символы приведены к нижнему регистру, то\n",
    "выводится соответствующая строка таблицы. \n",
    "\n",
    "Мы передаем переменную `code` методу `str.format()` один раз, но в\n",
    "строке формата она используется трижды. Первый раз – при выводе\n",
    "значения `code` как целого числа в поле с шириной 7 символов (по\n",
    "умолчанию в качестве символа-заполнителя используется пробел, поэтому\n",
    "нет необходимости явно указывать его). Второй раз – при выводе\n",
    "значения `code` как целого числа в шестнадцатеричном формате символами\n",
    "верхнего регистра в поле шириной 5 символов. И третий раз – при выводе \n",
    "символа Юникода, соответствующего значению code, с помощью\n",
    "спецификатора формата `c`, отцентрированного в поле с минимальной \n",
    "шириной 3 символа. Обратите внимание, что нам не потребовалось\n",
    "указывать тип `d` в первом спецификаторе формата, потому что он\n",
    "подразумевается по умолчанию для целых чисел. Второй аргумент –\n",
    "это имя символа Юникода, которое выводится с помощью метода\n",
    "`str.title()`, в результате которого первый символ каждого слова\n",
    "преобразуется к верхнему регистру, а остальные символы – к нижнему. \n",
    "\n",
    "\n",
    "## Решение квадратного уравнения\n",
    "<div id=\"datatype:examples:quadratic\"></div>\n",
    "\n",
    "Квадратные уравнения – это уравнения вида $ax^2 + bx + c = 0$, где $a \\ne 0$,\n",
    "описывающие параболу. Корни таких уравнений находятся по формуле"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$\n",
    "x = \\frac{-b \\pm \\sqrt{b^2-4ac}}{2a}.\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Часть формулы $b^2 – 4ac$ называется дискриминантом – если это\n",
    "положительная величина, уравнение имеет два действительных корня, если\n",
    "дискриминант равен нулю – уравнение имеет один действительный корень,\n",
    "и в случае отрицательного значения уравнение имеет два комплексных\n",
    "корня. Мы напишем программу, которая будет принимать от пользователя\n",
    "коэффициенты $a$, $b$ и $c$ (коэффициенты $b$ и c могут быть равны\n",
    "нулю) и затем вычислять и выводить его корень или корни.\n",
    "\n",
    "\n",
    "Для начала посмотрим, как работает программа:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "С коэффициентами $1.5$, $-3$ и $6$ программа выведет (некоторые цифры\n",
    "обрезаны):\n",
    "\n",
    "Теперь обратимся к [программному коду](src-datatype/quadratic.py),\n",
    "который начинается тремя инструкциями `import`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import cmath\n",
    "import math\n",
    "import sys"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Нам необходимы обе математические библиотеки для работы с числами типа\n",
    "`float` и `complex`, так как функции, вычисляющие квадратный \n",
    "корень из вещественных и комплексных чисел, отличаются. Модуль\n",
    "`sys` нам необходим, так как в нем определена константа\n",
    "`sys.float_info.epsilon`, которая потребуется нам для сравнения\n",
    "вещественных чисел со значением `0`.\n",
    "\n",
    "Нам также необходима функция, которая будет получать от пользова-\n",
    "теля число с плавающей точкой:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def get_float(msg, allow_zero):\n",
    "    x = None\n",
    "    while x is None:\n",
    "        try:\n",
    "            x = float(input(msg))\n",
    "            if not allow_zero and abs(x) < sys.float_info.epsilon:\n",
    "                print(\"zero is not allowed\")\n",
    "                x = None\n",
    "\n",
    "        except ValueError as err:\n",
    "            print(err)\n",
    "    return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Эта функция выполняет цикл, пока пользователь не введет допустимое\n",
    "число с плавающей точкой (например, `0.5`, `-9`, `21`, `4.92`), и допускает\n",
    "ввод значения `0`, только если аргумент `allow_zero` имеет значение `True`.\n",
    "Вслед за определением функции `get_float()` выполняется оставшаяся\n",
    "часть программного кода. Мы разделим его на три части и начнем со\n",
    "взаимодействия с пользователем:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(\"ax\\N{SUPERSCRIPT TWO} + bx + c = 0\")\n",
    "a = get_float(\"enter a: \", False)\n",
    "b = get_float(\"enter b: \", False)\n",
    "c = get_float(\"enter c: \", False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Благодаря функции `get_float()` получить значения коэффициентов `a`,\n",
    "`b` и `c` оказалось очень просто. Второй аргумент функции сообщает, когда\n",
    "значение `0` является допустимым."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "x1 = None\n",
    "x2 = None\n",
    "discriminant = (b ** 2) - (4 * a * c)\n",
    "if discriminant == 0:\n",
    "    x1 = -(b / (2 * a))\n",
    "else:\n",
    "    if discriminant > 0:\n",
    "        root = math.sqrt(discriminant)\n",
    "    else:       # discriminant < 0\n",
    "        root = cmath.sqrt(discriminant)\n",
    "        x1 = (-b + root) / (2 * a)\n",
    "        x2 = (-b - root) / (2 * a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Программный код выглядит несколько иначе, чем формула, потому\n",
    "что мы начали вычисления с определения значения дискриминанта.\n",
    "Если дискриминант равен `0`, мы знаем, что уравнение имеет\n",
    "единственное действительное решение и можно сразу же вычислить его. В\n",
    "противном случае мы вычисляем действительный или комплексный\n",
    "квадратный корень из дискриминанта и находим два корня уравнения."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "equation = (\"{0}x\\N{SUPERSCRIPT TWO} + {1}x + {2} = 0\"\n",
    "            \" \\N{RIGHTWARDS ARROW} x = {3}\").format(a, b, c, x1)\n",
    "if x2 is not None:\n",
    "    equation += \" or x = {0}\".format(x2)\n",
    "print(equation)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Мы не использовали сколько-нибудь сложного форматирования, поскольку\n",
    "форматирование, используемое по умолчанию для чисел с плавающей точкой\n",
    "в языке Python, прекрасно подходит для этого примера, но мы\n",
    "использовали некоторые имена Юникода для вывода пары специальных\n",
    "символов.\n",
    "\n",
    "## Представление таблицы `csv` в HTML\n",
    "<div id=\"datatype:examples:csv2html\"></div>\n",
    "\n",
    "Часто бывает необходимо представить данные в формате HTML. В этом\n",
    "подразделе мы разработаем программу, которая читает данные из\n",
    "файла в простом формате CSV (Comma Separated Value – значения,\n",
    "разделенные запятыми) и выводит таблицу HTML, содержащую эти\n",
    "данные. В составе Python присутствует мощный и сложный модуль\n",
    "для работы с форматом CSV и похожими на него – модуль csv, но здесь\n",
    "мы будем выполнять всю обработку вручную.\n",
    "\n",
    "В формате CSV каждая запись располагается на одной строке, а поля\n",
    "внутри записи отделяются друг от друга запятыми. Каждое поле может\n",
    "быть либо строкой, либо числом. Строки должны окружаться апострофами\n",
    "или кавычками, а числа не должны окружаться кавычками, если они не\n",
    "содержат запятые. Внутри строк допускается присутствие запятых, и они\n",
    "не должны интерпретироваться как разделители полей. Мы будем исходить\n",
    "из предположения, что первая запись в файле содержит имена полей. На\n",
    "выходе будет воспроизводиться таблица в формате HTML с выравниванием\n",
    "текста по левому краю (по умолчанию для HTML) и с выравниванием чисел\n",
    "по правому краю, по одной строке на запись и по одной ячейке на поле.\n",
    "\n",
    "Ниже приводится маленький фрагмент файла с данными:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "        \"COUNTRY\",2000,2001,2002,2003,2004\n",
    "        \"ANTIGUA AND BARBUDA\",0,0,0,0,0\n",
    "        \"ARGENTINA\",37,35,33,36,39\n",
    "        \"BAHAMAS, THE\",1,1,1,1,1\n",
    "        \"BAHRAIN\",5,6,6,6,6\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Предположим, что данные находятся в файле [sample.csv](src-datatype/sample.csv.txt) и выполнена комадна"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "        Terminal> python csv2html.py < sample.csv > sample.html\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "тогда файл [sample.html](src-datatype/sample.html) должен содержать\n",
    "примерно следующее:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "        <table border='1'>\n",
    "        <tr bgcolor='lightgreen'>\n",
    "        <td>\"Country\"</td>\n",
    "        <td align='right'>2000</td>\n",
    "        <td align='right'>2001</td>\n",
    "        <td align='right'>2002</td>\n",
    "        <td align='right'>2003</td>\n",
    "        <td align='right'>2004</td>\n",
    "        </tr>\n",
    "        <tr bgcolor='white'>\n",
    "        <td>\"Antigua and Barbuda\"</td>\n",
    "        <td align='right'>0</td>\n",
    "        <td align='right'>0</td>\n",
    "        <td align='right'>0</td>\n",
    "        <td align='right'>0</td>\n",
    "        <td align='right'>0</td>\n",
    "        </tr>\n",
    "        <tr bgcolor='lightyellow'>\n",
    "        <td>\"Argentina\"</td>\n",
    "        <td align='right'>37</td>\n",
    "        <td align='right'>35</td>\n",
    "        <td align='right'>33</td>\n",
    "        <td align='right'>36</td>\n",
    "        <td align='right'>39</td>\n",
    "        </tr>\n",
    "        <tr bgcolor='white'>\n",
    "        <td>\"Bahamas, The\"</td>\n",
    "        <td align='right'>1</td>\n",
    "        <td align='right'>1</td>\n",
    "        <td align='right'>1</td>\n",
    "        <td align='right'>1</td>\n",
    "        <td align='right'>1</td>\n",
    "        </tr>\n",
    "        <tr bgcolor='lightyellow'>\n",
    "        <td>\"Bahrain\"</td>\n",
    "        <td align='right'>5</td>\n",
    "        <td align='right'>6</td>\n",
    "        <td align='right'>6</td>\n",
    "        <td align='right'>6</td>\n",
    "        <td align='right'>6</td>\n",
    "        </tr>\n",
    "        </table>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "На рис. показано, как выглядит полученная таблица в веб-броузере.\n",
    "\n",
    "<!-- dom:FIGURE: [fig-datatype/example_1.png, width=400 frac=1.0] Таблица, произведенная программой [csv2html.py](src-datatype/csv2html.py), в броузере <div id=\"datatype:examples:fig:1\"></div> -->\n",
    "<!-- begin figure -->\n",
    "<div id=\"datatype:examples:fig:1\"></div>\n",
    "![Таблица, произведенная программой [csv2html.py](src-datatype/csv2html.py), в броузере](fig-datatype/example_1.png)<!-- end figure -->\n",
    "\n",
    "\n",
    "Теперь, когда мы увидели, как используется программа и что она делает,\n",
    "можно приступать к изучению программного кода.\n",
    "\n",
    "Последняя инструкция в программе – это простой вызов функции:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Хотя в языке Python не требуется явно указывать точку входа в\n",
    "программу, как в некоторых других языках программирования, тем не\n",
    "менее является распространенной практикой создание в программе на\n",
    "языке Python функции с именем `main()`, которая вызывается для\n",
    "выполнения обработки. Поскольку функция не может вызываться до того,\n",
    "как она будет определена, мы должны вставлять вызов `main()` только\n",
    "после того, как данная функция будет определена. Порядок следования\n",
    "функций в файле (то есть порядок, в котором они создаются) не \n",
    "имеет значения.\n",
    "\n",
    "В программе [csv2html.py](src-datatype/csv2html.py) первой\n",
    "вызываемой функцией является функция `main()`, которая в свою очередь\n",
    "вызывает функции `print_start()` и `print_line()`. Функция\n",
    "`print_line()` вызывает функции `extract_fields()` и `escape_html()`.\n",
    "\n",
    "Когда интерпретатор Python читает файл, он начинает делать это с\n",
    "самого начала. Поэтому сначала будет выполнен импорт (если он есть),\n",
    "затем будет создана функция `main()`, а затем будут созданы остальные\n",
    "функции – в том порядке, в каком они следуют в файле. Когда\n",
    "интерпретатор, наконец, достигнет вызова `main()` в конце файла, все\n",
    "функции, которые вызываются функцией `main()` (и все функции, которые\n",
    "вызываются этими функциями), будут определены. Выполнение обработки,\n",
    "как и следовало ожидать, начинается в точке вызова функции `main()`.\n",
    "\n",
    "Рассмотрим все функции по порядку, начиная с функции `main()`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def main():\n",
    "    maxwidth = 100\n",
    "    print_start()\n",
    "    count = 0\n",
    "    while True:\n",
    "        try:\n",
    "            line = input()\n",
    "            if count == 0:\n",
    "                color = \"lightgreen\"\n",
    "            elif count % 2:\n",
    "                color = \"white\"\n",
    "            else:\n",
    "                color = \"lightyellow\"\n",
    "            print_line(line, color, maxwidth)\n",
    "            count += 1\n",
    "        except EOFError:\n",
    "            break\n",
    "    print_end()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Переменная `maxwidth` используется для хранения числа символов в\n",
    "ячейке. Если поле больше, чем это число, часть строки отсекается и на\n",
    "место отброшенного текста добавляется многоточие. Программный код\n",
    "функций `print_start()`, `print_line()` и `print_end()` будет приведен\n",
    "чуть ниже. Цикл while выполняет обход всех входных строк – это могут\n",
    "быть строки, вводимые пользователем с клавиатуры, но мы предполагаем,\n",
    "что данные будут перенаправлены из файла. Далее выбирается цвет фона и\n",
    "вызывается функция `print_line()`, которая выводит строку в виде строки\n",
    "таблицы в формате HTML."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def print_start():\n",
    "    print(\"<table border='1'>\")\n",
    "\n",
    "def print_end():\n",
    "    print(\"</table>\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Мы могли бы не создавать эти две функции и просто вставить\n",
    "соответствующие вызовы `print()` в функцию `main()`. Но мы предпочитаем\n",
    "выделять логику, так как это делает реализацию более гибкой, хотя\n",
    "в этом маленьком примере гибкость не имеет большого значения."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def print_line(line, color, maxwidth):\n",
    "    print(\"<tr bgcolor='{0}'>\".format(color))\n",
    "    fields = extract_fields(line)\n",
    "    for field in fields:\n",
    "        if not field:\n",
    "            print(\"<td></td>\")\n",
    "        else:\n",
    "            number = field.replace(\",\", \"\")\n",
    "            try:\n",
    "                x = float(number)\n",
    "                print(\"<td align='right'>{0:d}</td>\".format(round(x)))\n",
    "            except ValueError:\n",
    "                field = field.title()\n",
    "                field = field.replace(\" And \", \" and \")\n",
    "                field = escape_html(field)\n",
    "                if len(field) <= maxwidth:\n",
    "                    print(\"<td>{0}</td>\".format(field))\n",
    "                else:\n",
    "                    print(\"<td>{0:.{1}} ...</td>\".format(field, maxwidth))\n",
    "    print(\"</tr>\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Мы не можем использовать метод `str.split(\",\")` для разбиения каждой\n",
    "строки на поля, потому что запятые могут находиться внутри строк в\n",
    "кавычках. Поэтому мы возложили эту обязанность на функцию\n",
    "`extract_fields()`. Получив список строк полей (в виде строк без\n",
    "окружающих их кавычек), мы выполняем обход списка и создаем для \n",
    "каждого поля ячейку таблицы.\n",
    "\n",
    "Если поле пустое, мы выводим пустую ячейку. Если поле было заключено в\n",
    "кавычки, это может быть строка или число в кавычках, содержащее\n",
    "символы запятой, например `\"1,566\"`. Учитывая такую возможность, мы\n",
    "создаем копию поля без запятых и пытаемся преобразовать ее в число\n",
    "типа `float`. Если преобразование удалось, мы определяем выравнивание\n",
    "в ячейке по правому краю, а значение поля округляется до ближайшего\n",
    "целого, которое и выводится. Если преобразование не удалось,\n",
    "следовательно, поле содержит строку. В этом случае мы с помощью метода\n",
    "`str.title()` изменяем регистр символов и замещаем слово «And» на слово\n",
    "«and», устраняя побочный эффект действия метода \n",
    "`str.title()`. Затем выполняется экранирование специальных символов\n",
    "HTML и выводится либо поле целиком, либо первые `maxwidth` символов\n",
    "с добавлением многоточия. Простейшей альтернативой использованию\n",
    "вложенного поля замены в строке формата является получение \n",
    "среза строки, например:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(\"<td>{0} ...</td>\".format(field[:maxwidth]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Еще одно преимущество такого подхода состоит в том, что он требует\n",
    "меньшего объема ввода с клавиатуры."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def extract_fields(line):\n",
    "    fields = []\n",
    "    field = \"\"\n",
    "    quote = None\n",
    "    for c in line:\n",
    "        if c in \"\\\"'\":\n",
    "            if quote is None:  # начало строки в кавычках\n",
    "                quote = c\n",
    "            elif quote == c:  # конец строки в кавычках\n",
    "                quote = None\n",
    "            else:\n",
    "                field += c\n",
    "                # другая кавычка внутри строки в кавычках\n",
    "                continue\n",
    "        if quote is None and c == \",\":  # end of a field\n",
    "            fields.append(field)\n",
    "            field = \"\"\n",
    "        else:\n",
    "            field += c\n",
    "            # добавить символ в поле\n",
    "    if field:\n",
    "        fields.append(field)  # добавить последнее поле в список\n",
    "    return fields"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Эта функция читает символы из строки один за другим и накапливает\n",
    "список полей, где каждое поле – это строка без окружающих ее\n",
    "кавычек. Функция способна обрабатывать поля, не заключенные в кавычки,\n",
    "и поля, заключенные в кавычки или в апострофы, корректно обрабатывая\n",
    "запятые и кавычки (апострофы в строках, заключенных в кавычки, и\n",
    "кавычки в строках, заключенных в апострофы)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def escape_html(text):\n",
    "    text = text.replace(\"&\", \"&amp;\")\n",
    "    text = text.replace(\"<\", \"&lt;\")\n",
    "    text = text.replace(\">\", \"&gt;\")\n",
    "    return text"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Эта функция просто замещает каждый специальный символ HTML\n",
    "соответствующей ему сущностью языка HTML. В первую очередь, конечно,\n",
    "мы должны заменить символ амперсанда и угловые скобки, хотя порядок не\n",
    "имеет никакого значения. \n",
    "\n",
    "<!-- Local Variables: -->\n",
    "<!-- doconce-chapter-nickname: \"datatype\" -->\n",
    "<!-- doconce-section-nickname: \"examples\" -->\n",
    "<!-- End: -->\n",
    "# Упражнения\n",
    "<div id=\"datatype:exercises\"></div>\n",
    "\n",
    "\n",
    "\n",
    "<!-- --- begin exercise --- -->\n",
    "\n",
    "## Изменение вывода символов Юникода\n",
    "<div id=\"datatype:exercises:1\"></div>\n",
    "\n",
    "Измените программу `print_unicode.py` так, чтобы пользователь мог\n",
    "вводить в командной строке несколько разных слов и получать\n",
    "только те строки из таблицы символов Юникода, в которых содержатся все\n",
    "слова, указанные пользователем. Это означает, что мы сможем вводить\n",
    "такие команды:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print_unicode_ans.py greek symbol"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- --- begin hint in exercise --- -->\n",
    "\n",
    "**Подсказка.**\n",
    "Один из способов достижения поставленной цели состоит в том,\n",
    "чтобы заменить переменную `word` (которая может хранить `0`, `None` \n",
    "или строку) списком `words`. Не забудьте изменить информацию о порядке\n",
    "использования. В результате изменений не более десяти строк\n",
    "программного кода добавится и не более десяти строк изменится.\n",
    "\n",
    "<!-- --- end hint in exercise --- -->\n",
    "Имя файла: `print_unicode_ans.py`.\n",
    "\n",
    "<!-- --- end exercise --- -->\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "<!-- --- begin exercise --- -->\n",
    "\n",
    "## Изменение `quadratic.py`\n",
    "<div id=\"datatype:exercises:2\"></div>\n",
    "\n",
    "Измените программу `quadratic.py` так, чтобы она не выводила\n",
    "коэффициенты со значением `0.0`, а отрицательные коэффициенты\n",
    "выводились бы как `-n`, а не `+ - n`.\n",
    "Имя файла: `quadratic_ans.py`.\n",
    "\n",
    "<!-- --- end exercise --- -->\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "<!-- --- begin exercise --- -->\n",
    "\n",
    "## Использование функции `escape()`\n",
    "<div id=\"datatype:exercises:escape\"></div>\n",
    "\n",
    "Удалите функцию `escape_html()` из программы `cvs2html.py` и\n",
    "используйте вместо нее функцию `xml.sax.saxutils.escape()` из модуля \n",
    "`xml.sax.saxutils`.\n",
    "\n",
    "<!-- --- begin hint in exercise --- -->\n",
    "\n",
    "**Подсказка.**\n",
    "Для этого потребуется добавить одну новую строку\n",
    "(с инструкцией `import`), удалить пять строк (с ненужной функцией)\n",
    "и изменить одну строку (задействовать функцию\n",
    "`xml.sax.saxutils.escape()` вместо `escape_html()`).\n",
    "\n",
    "<!-- --- end hint in exercise --- -->\n",
    "Имя файла: `cvs2html_ans1.py`.\n",
    "\n",
    "<!-- --- end exercise --- -->\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "<!-- --- begin exercise --- -->\n",
    "\n",
    "## Добавление обработки параметров командной строки в `csv2html.py`\n",
    "<div id=\"datatype:exercises:process_option\"></div>\n",
    "\n",
    "Измените программу `cvs2html.py` еще раз и добавьте в нее новую\n",
    "функцию с именем `process_options()`. Эта функция должна вызываться из\n",
    "функции main() и возвращать кортеж с двумя значениями: \n",
    "`maxwidth` (типа `int`) и `format` (типа `str`). При вызове функция\n",
    "`process_options()` должна устанавливать `maxwidth` в значение по\n",
    "умолчанию `100`, а строку `format` – в значение по умолчанию `\".0f\"`,\n",
    "которое будет использоваться как спецификатор формата при выводе чисел.\n",
    "Если пользователь вводит в командной строке `-h` или `--help`,\n",
    "должно выводиться сообщение о порядке использования и возвращаться\n",
    "кортеж `(None, None)`. (В этом случае функция `main()` ничего\n",
    "делать не должна.) В противном случае функция должна прочитать\n",
    "аргументы командной строки и выполнить соответствующие\n",
    "присваивания. Например, устанавливать значение переменной `maxwidth`,\n",
    "если задан аргумент `maxwidth=n`, и точно так же устанавливать \n",
    "значение переменной `format`, если задан аргумент `format=s`. Ниже\n",
    "приводится сеанс работы с программой, когда пользователь затребовал\n",
    "инструкцию о порядке работы:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "        Terminal> csv2html2_ans.py -h\n",
    "        usage:\n",
    "        csv2html.py [maxwidth=int] [format=str] < infile.csv > outfile.html\n",
    "        maxwidth - необязательное целое число. Если задано, определяет\n",
    "        максимальное число символов для строковых полей. В противном случае\n",
    "        используется значение по умолчанию 100.\n",
    "        \n",
    "        format - формат вывода чисел. Если не задан, по умолчанию используется\n",
    "        формат \".0f\".\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "А ниже приводится пример командной строки, в которой установ-\n",
    "лены оба аргумента:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "        Terminal> csv2html2_ans.py maxwidth=20 format=0.2f < mydata.csv > mydata.html\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- --- begin hint in exercise --- -->\n",
    "\n",
    "**Подсказка.**\n",
    "Не забудьте изменить функцию `print_line()` так, чтобы она\n",
    "использовала переменную `format` при выводе чисел – для этого вам\n",
    "придется передавать функции дополнительный аргумент, добавить одну \n",
    "строку и изменить еще одну строку. И это немного затронет функцию\n",
    "`main()`. Функция `process_options()` должна содержать порядка\n",
    "двадцати пяти строк (включая девять строк с текстом сообщения о\n",
    "порядке использования).\n",
    "\n",
    "<!-- --- end hint in exercise --- -->\n",
    "Имя файла: `cvs2html_ans2.py`.\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "<!-- Local Variables: -->\n",
    "<!-- doconce-chapter-nickname: \"datatype\" -->\n",
    "<!-- doconce-section-nickname: \"exercises\" -->\n",
    "<!-- End: -->\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "<!-- Local Variables: -->\n",
    "<!-- doconce-chapter-nickname: \"datatype\" -->\n",
    "<!-- End: -->\n",
    "<!-- --- end exercise --- -->"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 2
}
