diff --git a/arithmetic.ipynb b/arithmetic.ipynb
deleted file mode 100644
index ba393c2..0000000
--- a/arithmetic.ipynb
+++ /dev/null
@@ -1,926 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "\n",
- "# Арифметические операции\n",
- "\n",
- " \n",
- "**С.В. Лемешевский** (email: `sergey.lemeshevsky@gmail.com`), Институт математики НАН Беларуси\n",
- "\n",
- "\n",
- "Язык Python , благодаря наличию огромного количества библиотек для решения\n",
- "разного рода вычислительных задач, является конкурентом таким пакетам как Matlab и\n",
- "Octave. Запущенный в интерактивном режиме, он, фактически, превращается в\n",
- "мощный калькулятор. В этой главе речь пойдет об арифметических операциях,\n",
- "доступных в данном языке.\n",
- "\n",
- "Как было сказано в предыдущей главе, посвященной типам и модели данных\n",
- "Python, в этом языке существует три встроенных числовых типа данных:\n",
- "* целые числа (`int`);\n",
- "\n",
- "* вещественные числа (`float`);\n",
- "\n",
- "* комплексные числа (`complex`).\n",
- "\n",
- "Если в качестве операндов некоторого арифметического выражения используются\n",
- "только целые числа, то результат тоже будет целое число. Исключением является\n",
- "операция деления, результатом которой является вещественное число.\n",
- "При совместном использовании целочисленных и вещественных переменных, результат\n",
- "будет вещественным.\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "# Арифметические операции с целыми и вещественными числами\n",
- "
\n",
- "\n",
- "Все эксперименты будем проводить в Python, запущенном в интерактивном\n",
- "режиме.\n",
- "\n",
- "\n",
- "**Сложение.** Складывать можно непосредственно сами числа ..."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "3 + 2"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "либо переменные, но они должны предварительно быть проинициализированы."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "a = 3\n",
- "b = 2\n",
- "a + b"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Результат операции сложения можно присвоить другой переменной..."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "a = 3\n",
- "b = 2\n",
- "c = a + b\n",
- "print (c)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "либо ей же самой, в таком случае можно использовать полную или сокращенную\n",
- "запись, полная выглядит так:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "a = 3\n",
- "b = 2\n",
- "a = a + b\n",
- "print (a)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "сокращенная так:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "a = 3\n",
- "b = 2\n",
- "a += b\n",
- "print (a)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Все перечисленные выше варианты использования операции сложения могут быть\n",
- "применены для всех нижеследующих операций.\n",
- "\n",
- "**Вычитание.**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "4 - 2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "a = 5\n",
- "b = 7\n",
- "a - b"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Деление.**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "9 / 3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "a = 7\n",
- "b = 4\n",
- "a / b"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Получение целой части от деления.**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "9 // 3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "a = 7\n",
- "b = 4\n",
- "a // b"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Получение дробной части от деления.**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "9 % 5"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "a = 7\n",
- "b = 4\n",
- "a % b"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Возведение в степень.**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "5**4"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "a = 4\n",
- "b = 3\n",
- "a**b"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "\n",
- "\n",
- "\n",
- "\n",
- "# Работа с комплексными числами\n",
- "\n",
- "\n",
- "Для создания комплексного числа можно использовать функцию `complex(a, b)`, в\n",
- "которую, в качестве первого аргумента, передается действительная часть, в качестве\n",
- "второго – мнимая. Либо записать число в виде `a+bj`.\n",
- "\n",
- "Рассмотрим несколько примеров.\n",
- "\n",
- "Создание комплексного числа."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "z = 1+2j\n",
- "print(z)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 17,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "x = complex(3, 2)\n",
- "print(x)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Комплексные числа можно складывать, вычитать, умножать, делить и возводить в\n",
- "степень."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 18,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "x+z"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 19,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "x-z"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 20,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "x*z"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "x/z"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 22,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "x**z"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 23,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "x**3"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "У комплексного числа можно извлечь действительную и мнимую части."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 24,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "x = 3+2j\n",
- "x.real"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 25,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "x.imag"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Для получения комплексносопряженного число необходимо использовать метод\n",
- "`conjugate()`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 26,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "x.conjugate()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "\n",
- "\n",
- "\n",
- "\n",
- "# Битовые операции\n",
- "\n",
- "\n",
- "В Python доступны битовые операции, их можно производить над целыми числами.\n",
- "\n",
- "**Побитовое И (AND).**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 27,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "p = 9\n",
- "q = 3\n",
- "p & q"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Побитовое ИЛИ (OR).**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 28,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "p | q"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Побитовое Исключающее ИЛИ (XOR).**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 29,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "p^q"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Инверсия.**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 30,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "~p"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Сдвиг вправо и влево.**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 31,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "p<<1"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "\n",
- "\n",
- "\n",
- "\n",
- "# Представление чисел в других системах счисления\n",
- "\n",
- "\n",
- "В своей повседневной жизни мы используем десятичную систему исчисления, но\n",
- "при программирования, очень часто, приходится работать с шестнадцатеричной,\n",
- "двоичной и восьмеричной.\n",
- "\n",
- "**Представление числа в шестнадцатеричной системе.**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 32,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "m = 124504\n",
- "hex(m)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Представление числа в восьмеричной системе.**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 33,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "oct(m)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Представление числа в двоичной системе.**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 34,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "bin(m)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "\n",
- "\n",
- "\n",
- "\n",
- "# Библиотека (модуль) `math`\n",
- "\n",
- "\n",
- "В стандартную поставку Python входит библиотека math , в которой содержится\n",
- "большое количество часто используемых математических функций.\n",
- "\n",
- "Для работы с данным модулем его предварительно нужно импортировать."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 35,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "import math"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Рассмотрим наиболее часто используемые функции.\n",
- "\n",
- "**Функция `math.ceil(x)`.**\n",
- "\n",
- "Возвращает ближайшее целое число большее, чем `x`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 36,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.ceil(3.2)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Функция `math.fabs(x)`.**\n",
- "\n",
- "Возвращает абсолютное значение числа."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 37,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.fabs(-7)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Функция `math.factorial(x)`.**\n",
- "\n",
- "Вычисляет факториал `x`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 38,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.factorial(5)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "** Функция `math.floor(x)`.**\n",
- "\n",
- "Возвращает ближайшее целое число меньшее, чем `x`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 39,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.floor(3.2)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Функция `math.exp(x)`.**\n",
- "Вычисляет `e**x`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 40,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.exp(3)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Функция `math.log2(x)`.**\n",
- "Логарифм по основанию `2`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 41,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.log2(8)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Функция `math.log10(x)`.**\n",
- "\n",
- "Логарифм по основанию 10."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 42,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.log10(1000)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Функция `math.log(x[, base])`.**\n",
- "\n",
- "По умолчанию вычисляет логарифм по основанию `e`, дополнительно можно указать\n",
- "основание логарифма."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 43,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.log(5)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 44,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.log()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Функция `math.pow(x, y)`.**\n",
- "\n",
- "Вычисляет значение `x` в степени `y`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 45,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.pow(3 , 4)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Функция `math.sqrt(x)`.**\n",
- "\n",
- "Корень квадратный от `x`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 46,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "math.sqrt(25)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Тригонометрические функции, их мы оставим без примера.**\n",
- "\n",
- "* `math.cos(x)`\n",
- "\n",
- "* `math.sin(x)`\n",
- "\n",
- "* `math.tan(x)`\n",
- "\n",
- "* `math.acos(x)`\n",
- "\n",
- "* `math.asin(x)`\n",
- "\n",
- "* `math.atan(x)`\n",
- "\n",
- "И напоследок пару констант.\n",
- "* `math.pi` — число $\\pi$.\n",
- "\n",
- "* `math.e` — число $e$.\n",
- "\n",
- "Помимо перечисленных, модуль `math` содержит ещё много различных\n",
- "функций, за более подробной информацией можете обратиться eна\n",
- "официальный сайт ().\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "\n",
- ""
- ]
- }
- ],
- "metadata": {},
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/collections.ipynb b/collections.ipynb
new file mode 100644
index 0000000..3cd433e
--- /dev/null
+++ b/collections.ipynb
@@ -0,0 +1,1907 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "# Тыпы коллекций\n",
+ "\n",
+ " \n",
+ "**С.В. Лемешевский** (email: `sergey.lemeshevsky@gmail.com`), Институт математики НАН Беларуси\n",
+ "\n",
+ "Date: **Mar 2, 2020**\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "Рассматриваются кортежи и списки, а также новые типы коллекций, включая словари и множества.\n",
+ "\n",
+ "# Последовательности\n",
+ "\n",
+ "\n",
+ "Последовательности – это один из типов данных, поддерживающих\n",
+ "оператор проверки на вхождение (`in`), функцию определения размера\n",
+ "(`len()`), оператор извлечения срезов (`[]`) и возможность выполнения\n",
+ "итераций. В языке Python имеется пять встроенных типов\n",
+ "последовательностей: `bytearray`, `bytes`, `list`, `str` и\n",
+ "`tuple`. Ряд дополнительных типов последовательностей реализован в\n",
+ "стандартной библиотеке; наиболее примечательным \n",
+ "из них является тип `collections.namedtuple`. При выполнении итераций\n",
+ "все эти последовательности гарантируют строго определенный порядок\n",
+ "следования элементов.\n",
+ "\n",
+ "Строки мы уже рассматривали выше, а в этом разделе познакомимся с\n",
+ "кортежами, именованными кортежами и списками.\n",
+ "\n",
+ "## Кортежи\n",
+ "\n",
+ "\n",
+ "Кортеж – это упорядоченная последовательность из нуля или более ссылок\n",
+ "на объекты. Кортежи поддерживают тот же синтаксис получения срезов,\n",
+ "что и строки. Это упрощает извлечение элементов из кортежа. Подобно\n",
+ "строкам, кортежи относятся к категории неизменяемых объектов, поэтому\n",
+ "мы не можем замещать или удалять какие-либо их элементы. Если нам\n",
+ "необходимо иметь возможность изменять упорядоченную\n",
+ "последовательность, то вместо кортежей можно просто использовать\n",
+ "списки или, если в программе уже используется кортеж, который\n",
+ "нежелательно модифицировать, можно преобразовать кортеж в список с\n",
+ "помощью функции преобразования `list()` и затем изменять полученный\n",
+ "список.\n",
+ "\n",
+ "Тип данных `tuple` может вызываться как функция `tuple()` – без\n",
+ "аргументов она возвращает пустой кортеж, с аргументом типа tuple\n",
+ "возвращает поверхностную копию аргумента; в случае, если аргумент\n",
+ "имеет другой тип, выполняется попытка преобразовать его в объект\n",
+ "типа `tuple`. Эта функция принимает не более одного аргумента. Кроме\n",
+ "того, кортежи могут создаваться без использования функции\n",
+ "`tuple()`. Пустой кортеж создается с помощью пары пустых круглых\n",
+ "скобок `()`, а кортеж, состоящий из одного или более элементов, может быть\n",
+ "создан с помощью запятых. Иногда кортежи приходится заключать в\n",
+ "круглые скобки, чтобы избежать синтаксической\n",
+ "неоднозначности. Например, чтобы передать кортеж `1, 2, 3` в функцию,\n",
+ "необходимо использовать такую форму записи: `function((1, 2, 3))`.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "На рис. [collections:seq:fig:1](#collections:seq:fig:1) показан кортеж\n",
+ "`t = \"venus\", – 28, \"green\", \"21\", 19.74` и индексы элементов внутри кортежа. Строки\n",
+ "индексируются точно так же, но, если в строках каждой позиции\n",
+ "соответствует единственный символ, то в кортежах каждой позиции\n",
+ "соответствует единственная ссылка на объект.\n",
+ "\n",
+ "Кортежи предоставляют всего два метода: `t.count(x)`, который\n",
+ "возвращает количество объектов `x` в кортеже `t`, и `t.index(x)`,\n",
+ "который возвращает индекс самого первого (слева) вхождения объекта `x`\n",
+ "в кортеж `t` или возбуждает исключение `ValueError`, если объект `x`\n",
+ "отсутствует в кортеже. (Эти методы имеются также и у списков.)\n",
+ "\n",
+ "Кроме того, кортежи могут использоваться с оператором `+`\n",
+ "(конкатенации), `*` (дублирования) и `[]` (получения среза), а\n",
+ "операторы `in` и `not in` могут применяться для проверки на\n",
+ "вхождение. Можно использовать также комбинированные операторы\n",
+ "присваивания `+=` и `*=`. Несмотря на то, что кортежи являются\n",
+ "неизменяемыми объектами, при выполнении этих операторов интерпретатор\n",
+ "Python создает за кулисами новый кортеж с результатом операции и\n",
+ "присваивает ссылку на него объекту, расположенному слева от оператора,\n",
+ "то есть используется тот же самый прием, что и со строками. Кортежи\n",
+ "могут сравниваться с помощью стандартных операторов сравнения (`<`,\n",
+ "`<=`, `==`, `!=`, `>=`, `>`), при этом сравнивание производится\n",
+ "поэлементно (и рекурсивно, при наличии вложенных элементов, таких как\n",
+ "кортежи в кортежах).\n",
+ "\n",
+ "Рассмотрим несколько примеров получения срезов, начав с извлечения\n",
+ "единственного элемента и группы элементов:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "hair = \"black\", \"brown\", \"blonde\", \"red\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "hair[2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "hair[-3:] # то же, что и hair[1:]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Эта операция выполняется точно так же, как и в случае со строками,\n",
+ "списками или любыми другими последовательностями."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "hair[:2], \"gray\", hair[2:]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Здесь мы попытались создать новый кортеж из 5 элементов, но в\n",
+ "результате получили кортеж с тремя элементами, содержащий два\n",
+ "двухэлементных кортежа. Это произошло потому, что мы применили\n",
+ "оператор запятой к трем элементам (кортеж, строка и кортеж). Чтобы\n",
+ "получить единый кортеж со всеми этими элементами, необходимо выполнить\n",
+ "конкатенацию кортежей:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "hair[:2] + (\"gray\",) + hair[2:]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Чтобы создать кортеж из одного элемента, необходимо поставить запятую,\n",
+ "но если запятую просто добавить, будет получено исключение `TypeError`\n",
+ "(так как интерпретатор будет думать, что выполняется конкатенация\n",
+ "строки и кортежа), поэтому необходимо использовать запятую и круглые\n",
+ "скобки.\n",
+ "\n",
+ "Коллекции допускают возможность вложения с любой глубиной\n",
+ "вложенности. Оператор извлечения срезов `[]` может применяться для\n",
+ "доступа к вложенным коллекциям столько раз, сколько это будет\n",
+ "необходимо. Например:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "things = (1, -7.5, (\"pea\", (5, \"Xyz\"), \"queue\"))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "things[2][1][1][2]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Кортежи могут хранить элементы любых типов, включая другие коллекции,\n",
+ "такие как кортежи и списки, так как на самом деле кортежи хранят\n",
+ "ссылки на объекты. Использование сложных, вложенных структур данных,\n",
+ "таких, как показано ниже, легко может создавать путаницу. Одно из\n",
+ "решений этой проблемы состоит в том, чтобы давать значениям индексов\n",
+ "осмысленные имена. Например:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "MANUFACTURER, MODEL, SEATING = (0, 1, 2)\n",
+ "MINIMUM, MAXIMUM = (0, 1)\n",
+ "aircraft = (\"Airbus\", \"A320-200\", (100, 220))\n",
+ "aircraft[SEATING][MAXIMUM]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "В первых двух строках вышеприведенного фрагмента мы выполнили\n",
+ "присваивание кортежам. Когда справа от оператора присваивания\n",
+ "указывается последовательность (в данном случае – это кортежи),\n",
+ "а слева указан кортеж, мы говорим, что последовательность справа\n",
+ "*распаковывается*. Операция распаковывания последовательностей\n",
+ "может использоваться для организации обмена значений между\n",
+ "переменными, например:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "a, b = (b, a)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Именованные кортежы\n",
+ "\n",
+ "\n",
+ "Именованные кортежи ведут себя точно так же, как и обычные кортежи, и\n",
+ "не уступают им в производительности. Отличаются они возможностью\n",
+ "ссылаться на элементы кортежа не только по числовому индексу, но и по\n",
+ "имени, что в свою очередь позволяет создавать сложные агрегаты из\n",
+ "элементов данных.\n",
+ "\n",
+ "В модуле `collections` имеется функция `namedtuple()`. Эта функция\n",
+ "используется для создания собственных типов кортежей. Например:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "import collections\n",
+ "Sale = collections.namedtuple(\"Sale\", \"productid customerid date quantity price\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Первый аргумент функции `collections.namedtuple()` – это имя\n",
+ "создаваемого кортежа. Второй аргумент – это строка имен, разделенных\n",
+ "пробелами, для каждого элемента, который будет присутствовать в этом\n",
+ "кортеже. Первый аргумент и имена во втором аргументе должны быть\n",
+ "допустимыми идентификаторами языка Python. Функция возвращает класс\n",
+ "(тип данных), который может использоваться для создания именованных\n",
+ "кортежей. Так, в примере выше мы можем интерпретировать имя `Sale` как\n",
+ "имя любого другого класса (такого как `tuple`) в языке Python и\n",
+ "создавать объекты типа `Sale`. Например:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "sales = []\n",
+ "sales.append(Sale(432, 921, \"2008-09-14\", 3, 7.99))\n",
+ "sales.append(Sale(419, 874, \"2008-09-15\", 1, 18.49))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "В этом примере мы создали список из двух элементов типа `Sale`, то\n",
+ "есть из двух именованных кортежей. Мы можем обращаться к элементам\n",
+ "таких кортежей по их индексам – например, обратиться к элементу\n",
+ "`price` в первом элементе списка `sales` можно с помощью выражения\n",
+ "`sales[0][-1]` (вернет значение `7.99`) – или по именам, которые\n",
+ "делают программный код более удобочитаемым:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "total = 0\n",
+ "for sale in sales:\n",
+ " total += sale.quantity*sale.price\n",
+ "print(\"Total {0:.2f}\".format(total))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Очень часто простоту и удобство, которые предоставляют именованные\n",
+ "кортежи, можно обратить на пользу делу. Например, ниже приводится\n",
+ "версия примера `aircraft` из предыдущего подраздела, имеющая более\n",
+ "аккуратный вид:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "Aircraft = collections.namedtuple(\"Aircraft\", \"manufacturer model seating\")\n",
+ "Seating = collections.namedtuple(\"Seating\", \"minimum maximum\")\n",
+ "aircraft = Aircraft(\"Airbus\", \"A320-200\", Seating(100, 220))\n",
+ "aircraft.seating.maximum"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Списки\n",
+ "\n",
+ "\n",
+ "Список – это упорядоченная последовательность из нуля\n",
+ "или более ссылок на объекты. Списки поддерживают тот\n",
+ "же синтаксис получения срезов, что и строки с кортежами. Это упрощает\n",
+ "извлечение элементов из списка. В отличие от строк и кортежей списки\n",
+ "относятся к категории изменяемых объектов, поэтому мы можем замещать\n",
+ "или удалять любые их элементы. Кроме того, существует возможность\n",
+ "вставлять, замещать и удалять целые срезы списков.\n",
+ "\n",
+ "Тип данных `list` может вызываться как функция `list()` –\n",
+ "без аргументов она возвращает пустой список, с аргументом типа `list`\n",
+ "возвращает поверхностную копию аргумента; в случае, если аргумент\n",
+ "имеет другой тип, выполняется попытка преобразовать его в объект типа\n",
+ "`list`. Эта функция принимает не более одного аргумента. Кроме того,\n",
+ "списки могут создаваться без использования функции `list()`. Пустой\n",
+ "список создается с помощью пары пустых квадратных скобок `[]`, а список,\n",
+ "состоящий из одного или более элементов, может быть создан с помощью\n",
+ "последовательности элементов, разделенных запятыми, заключенной в\n",
+ "квадратные скобки. Другой способ создания списков заключается в\n",
+ "использовании генераторов списков – эта тема будет рассматриваться\n",
+ "ниже в этом подразделе.\n",
+ "\n",
+ "Поскольку все элементы списка в действительности являются ссылками на\n",
+ "объекты, списки, как и кортежи, могут хранить элементы любых типов\n",
+ "данных, включая коллекции, такие как списки и кортежи. Списки могут\n",
+ "сравниваться с помощью стандартных операторов сравнения (`<`, `<=`,\n",
+ "`==`, `!=`, `>=`, `>`), при этом сравнивание производится поэлементно\n",
+ "(и рекурсивно, при наличии вложенных элементов, таких как списки или\n",
+ "кортежи в списках).\n",
+ "\n",
+ "В результате выполнения операции присваивания\n",
+ "`L = [ – 17.5, \"kilo\", 49, \"V\", [\"ram\", 5, \"echo\"], 7]` мы получим\n",
+ "список, как показано на рис. [collections:seq:fig:2](#collections:seq:fig:2)\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "К спискам, таким как `L`, мы можем применять оператор извлечения\n",
+ "среза, повторяя его столько раз, сколько потребуется для доступа к\n",
+ "элементам в списке, как показано ниже:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "L[0] == L[-6] == -17.5\n",
+ "L[1] == L[-5] == 'kilo'\n",
+ "L[1][0] == L[-5][0] == 'k'\n",
+ "L[4][2] == L[4][-1] == L[-2][2] == L[-2][-1] == 'echo'\n",
+ "L[4][2][1] == L[4][2][-3] == L[-2][-1][1] == L[-2][-1][-3] == 'c'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Списки, как и кортежи, могут вкладываться друг в друга; допускают\n",
+ "выполнение итераций по их элементам и извлечение срезов. Все примеры с\n",
+ "кортежами, которые приводились в предыдущем подразделе, будут работать\n",
+ "точно так же, если вместо кортежей в них будут использованы\n",
+ "списки. Списки поддерживают операторы проверки на вхождение `in` и\n",
+ "`not in`, оператор конкатенации `+`, оператор расширения `+=` (то есть\n",
+ "добавляет операнд справа в конец списка) и операторы дублирования `*`\n",
+ "и `*=`. Списки могут также использоваться в качестве аргументов\n",
+ "функции `len()`.\n",
+ "\n",
+ "Кроме того, списки предоставляют методы, перечисленные в\n",
+ "табл. [collections:seq:tbl:1](#collections:seq:tbl:1) \n",
+ "\n",
+ "\n",
+ "## Таблица 1 : Методы списков \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "| Синтаксис | Описание |
\n",
+ "\n",
+ "\n",
+ " L.append(x) | Добавляет элемент x в конец списка L |
\n",
+ " L.count(x) | Возвращает число вхождений элемента x в список L |
\n",
+ " L.extend(m) или L += m | Добавляет в конец списка L все элементы итерируемого объекта m |
\n",
+ " L.index(x, start, end) | Возвращает индекс самого первого (слева) вхождения элемента x в список L (или в срез start:end списка L); в противном случае возбуждает исключение ValueError |
\n",
+ " L.insert(i, x) | Вставляет элемент x в список L в позицию int i |
\n",
+ " L.pop() | Удаляет самый последний элемент из списка L и возвращает его в качестве результата |
\n",
+ " L.pop(i) | Удаляет из списка L элемент с индексом int i и возвращает его в качестве результата |
\n",
+ " L.remove(x) | Удаляет самый первый (слева) найденный элемент x из списка L или возбуждает исключение ValueError, если элемент xне будет найден |
\n",
+ " L.reverse() | Переставляет в памяти элементы списка в обратном порядке |
\n",
+ " L.sort() | Сортирует список в памяти. Этот метод принимает те же необязательные аргументы key и reverse что и встроенная функция sorted()` |
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "\n",
+ "Несмотря на то, что для доступа к элементам списка можно использовать\n",
+ "оператор извлечения среза, тем не менее в некоторых ситуациях бывает\n",
+ "необходимо одновременно извлечь две или более частей списка. \n",
+ "Сделать это можно с помощью операции распаковывания\n",
+ "последовательности. Любой итерируемый объект (списки, кортежи и\n",
+ "другие) может быть распакован с помощью оператора распаковывания\n",
+ "«звездочка» (`*`). Когда слева от оператора присваивания указывается\n",
+ "две или более переменных, одна из которых предваряется символом `*`,\n",
+ "каждой переменной присваивается по одному элементу списка, а\n",
+ "переменной со звездочкой присваивается оставшаяся часть списка. Ниже\n",
+ "приводится несколько примеров выполнения распаковывания списков:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "first, *rest = [9, 2, -4, 8, 7]\n",
+ "first, rest"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "first, *mid, last = \"Charles Philip Arthur George Windsor\".split()\n",
+ "first, mid, last"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "*directories, executable = \"/usr/local/bin/gvim\".split(\"/\")\n",
+ "directories, executable"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Когда используется оператор распаковывания последовательности,\n",
+ "как в данном примере, выражение `*rest` и подобные ему называются\n",
+ "*выражениями со звездочкой*.\n",
+ "\n",
+ "В языке Python имеется также похожее понятие *аргументов со звездочкой*.\n",
+ "Например, допустим, что имеется следующая функция, принимающая три\n",
+ "аргумента:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "def product(a, b, c):\n",
+ " return a * b * c"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "тогда мы можем вызывать эту функцию с тремя аргументами или\n",
+ "использовать аргументы со звездочкой:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "product(2, 3, 5)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "L = [2, 3, 5]\n",
+ "product(*L)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "product(2, *L[1:])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "В первом примере функция вызывается, как обычно, с тремя\n",
+ "аргументами. Во втором вызове использован аргумент со звездочкой; в\n",
+ "этом случае список из трех элементов распаковывается оператором `*`,\n",
+ "так что функция получает столько аргументов, сколько ей\n",
+ "требуется. Того же эффекта можно было бы добиться при использовании\n",
+ "кортежа с тремя элементами. В третьем вызове функции первый аргумент\n",
+ "передается традиционным способом, а другие два – посредством\n",
+ "применения операции распаковывания двухэлементного среза списка `L`. \n",
+ "\n",
+ "Имеется возможность выполнять итерации по элементам списка с помощью\n",
+ "конструкции `for item in L:`. Если в цикле потребуется изменять\n",
+ "элементы списка, то можно использовать следующий прием:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "for i in range(len(L)):\n",
+ " L[i] = process(L[i])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "> **Замечание.**\n",
+ ">\n",
+ "> Встроенная функция `range()` возвращает целочисленный\n",
+ "> итератор. С одним целочисленным аргументом, `n`, итератор `range()`\n",
+ "> возвращает последовательность чисел $0$, $1$, ..., $n-1$.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "Этот прием можно использовать для увеличения всех элементов в списке\n",
+ "целых чисел. Например:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "for i in range(len(numbers)):\n",
+ " numbers[i] += 1"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Генераторы списков\n",
+ "\n",
+ "\n",
+ "\n",
+ "Небольшие списки часто создаются как литералы, но длинные списки\n",
+ "обычно создаются программным способом. Списки целых чисел могут\n",
+ "создаваться с помощью выражения `list(range(n))`; когда необходим\n",
+ "итератор целых чисел, достаточно функции `range()`; а для создания\n",
+ "списков других типов часто используется оператор цикла `for ... in`.\n",
+ "Предположим, например, что нам требуется получить список високосных\n",
+ "годов в определенном диапазоне. Для начала мы могли бы использовать\n",
+ "такой цикл:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "leaps = []\n",
+ "for year in range(1900, 1940):\n",
+ " if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):\n",
+ " leaps.append(year)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Когда функции `range()` передаются два целочисленных\n",
+ "аргумента `n` и `m`, итератор возвращает последовательность целых\n",
+ "чисел `n`, `n+1`, ..., `m–1`. \n",
+ "\n",
+ "Конечно, если диапазон известен заранее, можно было\n",
+ "бы использовать литерал списка, например,\n",
+ "`leaps = [1904, 1908, 1912, 1916, 1920, 1924, 1928, 1932, 1936]`.\n",
+ "\n",
+ "*Генератор списков* – это выражение и цикл с дополнительным условием,\n",
+ "заключенное в квадратные скобки, в котором цикл используется для\n",
+ "создания элементов списка, а условие используется для исключения\n",
+ "нежелательных элементов. В простейшем виде генератор списков\n",
+ "записывается, как показано ниже:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```Python\n",
+ " [item for item in iterable]\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Это выражение вернет список всех элементов объекта `iterable` и\n",
+ "семантически ничем не отличается от выражения\n",
+ "`list(iterable)`. Интересными генераторы списков делают две\n",
+ "особенности – они могут использоваться как выражения и они допускают\n",
+ "включение условной инструкции, вследствие чего мы получаем две\n",
+ "типичные синтаксические конструкции использования генераторов списков:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```Python\n",
+ " [expression for item in iterable]\n",
+ " [expression for item in iterable if condition]\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Вторая форма записи эквивалентна циклу:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```Python\n",
+ " temp = []\n",
+ " for item in iterable:\n",
+ " if condition:\n",
+ " temp.append(expression)\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Обычно выражение `expression` является либо самим элементом `item`,\n",
+ "либо некоторым выражением с его участием. Конечно, генератору\n",
+ "списков не требуется временная переменная `temp[]`, которая необходима\n",
+ "в версии с циклом `for ... in`.\n",
+ "\n",
+ "Теперь можно переписать программный код создания списка високосных\n",
+ "годов с использованием генератора списка. Мы сделаем это в три\n",
+ "этапа. Сначала создадим список, содержащий все годы в указанном\n",
+ "диапазоне:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "leaps = [y for y in range(1900, 1940)]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "То же самое можно было бы сделать с помощью выражения\n",
+ "`leaps = list(range(1900, 1940))`. Теперь добавим простое условие,\n",
+ "которое будет оставлять в списке только каждый четвертый год:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "leaps = [y for y in range(1900, 1940) if y % 4 == 0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "И, наконец, получаем окончательную версию:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "leaps = [y for y in range(1900, 1940)\n",
+ " if (y % 4 == 0 and y % 100 != 0) or (y % 400 == 0)]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Использование генератора списков в данном случае позволило уменьшить\n",
+ "объем программного кода с четырех строк до двух – не так много, но в\n",
+ "крупных проектах суммарная экономия может оказаться весьма\n",
+ "существенной. \n",
+ "\n",
+ "Так как генераторы списков воспроизводят списки, то есть итерируемые\n",
+ "объекты, и сами генераторы списков используют итерируемые объекты,\n",
+ "имеется возможность вкладывать генераторы списков друг \n",
+ "в друга. Это эквивалентно вложению циклов `for ... in`. Например, если\n",
+ "бы нам потребовалось сгенерировать список всех возможных кодов одежды\n",
+ "для разных полов, разных размеров и расцветок, но исключая одежду для\n",
+ "полных женщин, нужды и чаянья которых индустрия моды нередко\n",
+ "игнорирует, мы могли бы использовать вложенные циклы\n",
+ "`for ... in`, как показано ниже:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "codes = []\n",
+ "for sex in \"MF\":\n",
+ " for size in \"SMLX\":\n",
+ " \tif sex == \"F\" and size\n",
+ "\t continue\n",
+ " for color in \"BGW\":\n",
+ "\t codes.append(sex + size + color)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Этот фрагмент воспроизводит список, содержащий 21 элемент – `['MSB',\n",
+ "'MSG', ..., 'FLW']`. Тот же самый список можно создать парой строк,\n",
+ "если воспользоваться генераторами списков:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "codes = [s + z + c for s in \"MF\" for z in \"SMLX\" for c in \"BGW\"\n",
+ " if not (s == \"F\" and z == \"X\")]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Здесь каждый элемент списка воспроизводится выражением `s + z + c`.\n",
+ "Кроме того, в генераторе списков несколько иначе построена логика\n",
+ "обхода нежелательной комбинации пол/размер – проверка выполняется в\n",
+ "самом внутреннем цикле, тогда как в версии с циклами `for ... in` эта\n",
+ "проверка выполняется в среднем цикле. Любой генератор списков можно\n",
+ "переписать, используя один или более циклов `for ... in`. \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "# Множества\n",
+ "\n",
+ "\n",
+ "Тип `set` – это разновидность коллекций, которая поддерживает оператор\n",
+ "проверки на вхождение `in`, функцию `len()` и относится к разряду\n",
+ "итерируемых объектов. Кроме того, множества предоставляют метод \n",
+ "`set.isdisjoint()` и поддерживают операторы сравнения и битовые\n",
+ "операторы (которые в контексте множеств используются для получения \n",
+ "объединения, пересечения и т. д.). В языке Python имеется два\n",
+ "встроенных типа множеств: изменяемый тип `set` и неизменяемый\n",
+ "`frozenset`. При переборе элементов множества элементы могут следовать\n",
+ "в произвольном порядке. \n",
+ "\n",
+ "В состав множеств могут включаться только *хешируемые*\n",
+ "объекты. Хешируемые объекты – это объекты, имеющие специальный метод \n",
+ "`__hash__()`, на протяжении всего жизненного цикла объекта всегда\n",
+ "возвращающий одно и то же значение, которые могут участвовать в\n",
+ "операциях сравнения на равенство посредством специального метода \n",
+ "`__eq__()`. (Специальные методы – это методы, имена которых начинаются\n",
+ "и оканчиваются двумя символами подчеркивания).\n",
+ "\n",
+ "Все встроенные неизменяемые типы данных, такие как `float`,\n",
+ "`frozenset`, `int`, `str` и `tuple`, являются хешируемыми объектами и\n",
+ "могут добавляться во множества. Встроенные изменяемые типы данных,\n",
+ "такие как `dict`, `list` и `set`, не являются хешируемыми объектами,\n",
+ "так как значение хеша в каждом конкретном случае зависит от\n",
+ "содержащихся в объекте элементов, поэтому они не могут добавляться в\n",
+ "множества.\n",
+ "\n",
+ "Множества могут сравниваться между собой с использованием стандартных\n",
+ "операторов сравнения (`<`, `<=`, `==`, `!=`, `>=`, `>`). Обратите\n",
+ "внимание: операторы `==` и `!=` имеют обычный смысл, и сравнение\n",
+ "выполняется путем поэлементного сравнения (или рекурсивно при наличии\n",
+ "таких вложенных элементов, как кортежи и фиксированные множества\n",
+ "(`frozenset`)), но остальные операторы сравнения выполняют сравнение\n",
+ "подмножеств и надмножеств, как вскоре будет показано. \n",
+ "\n",
+ "## Тип `set`\n",
+ "\n",
+ "\n",
+ "Тип `set` – это неупорядоченная коллекция из нуля или более ссылок на\n",
+ "объекты, указывающих на хешируемые объекты. Множества относятся к\n",
+ "категории изменяемых типов, поэтому легко можно добавлять и удалять их\n",
+ "элементы, но, так как они являются неупорядоченными коллекциями, к ним\n",
+ "не применимо понятие индекса и не применима операция извлечения\n",
+ "среза. На рис. [collections:sets:fig:1](#collections:sets:fig:1) иллюстрируется множество,\n",
+ "созданное следующим фрагментом программного кода:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "S = {7, \"veil\", 0, -29, (\"x\", 11), \"sun\", frozenset({8, 4, 7}), 913}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "Тип данных `set` может вызываться как функция `set()` –\n",
+ "без аргументов она возвращает пустое множество; с аргументом типа\n",
+ "`set` возвращает поверхностную копию аргумента; в случае, если\n",
+ "аргумент имеет другой тип, выполняется попытка преобразовать его в\n",
+ "объект типа `set`. Эта функция принимает не более одного\n",
+ "аргумента. Кроме того, непустые множества могут создаваться без\n",
+ "использования функции `set()`, а пустые множества могут создаваться\n",
+ "только с помощью функции `set()` – их нельзя создать с помощью пары\n",
+ "пустых скобок. Множество, состоящее из одного или более элементов,\n",
+ "может быть создано с помощью последовательности элементов, разделенных\n",
+ "запятыми, заключенной в фигурные скобки. Другой способ создания\n",
+ "множеств заключается в использовании генераторов множеств. Множества\n",
+ "всегда содержат уникальные элементы – добавление повторяющихся\n",
+ "элементов возможно, но не имеет смысла. Например, следующие три\n",
+ "множества являются эквивалентными: `set(\"apple\")`, `set(\"aple\")` и\n",
+ "`{'e', 'p', 'a', 'l'}`. Благодаря этой их особенности множества часто\n",
+ "используются для устранения повторяющихся значений. Например, если\n",
+ "предположить, что `x` – это список строк, то после выполнения\n",
+ "инструкции `x = list(set(x))` в списке останутся только уникальные\n",
+ "строки, причем располагаться они могут в произвольном порядке.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "Множества поддерживают встроенную функцию `len()` и быструю проверку\n",
+ "на вхождение с помощью операторов `in` и `not in`. Они также предоставляют\n",
+ "типичный набор операторов, как показано на рис. . \n",
+ "Полный перечень методов и операторов, применимых к множествам,\n",
+ "приводится в табл. [collections:sets:tbl:1](#collections:sets:tbl:1). Все методы семейства\n",
+ "«update» (`set.update()`, `set.intersection_update()` и т. д.) могут принимать в качестве\n",
+ "аргумента любые итерируемые объекты, но эквивалентные им\n",
+ "комбинированные операторы присваивания (`|=`, `&=` и т. д.) требуют, чтобы\n",
+ "оба операнда были множествами. \n",
+ "\n",
+ "\n",
+ "## Таблица 2 : Методы и операторы множеств \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "| Синтаксис | Описание |
\n",
+ "\n",
+ "\n",
+ " s.add(x) | Добавляет элементы x во множество s, если они отсутствуют в s |
\n",
+ " s.clear() | Удаляет все элементы из множества s |
\n",
+ " s.difference(t)или s-t | Возвращает новое множество включающее элементы множества s, которые отсутствуют в множестве t |
\n",
+ " s.difference_update(t) или s-=t | Удаляет из множества s все элементы, присутствующие в множестве t |
\n",
+ " s.discard(x) | Удаляет элемент x из множества s, если он присутствует в множестве s |
\n",
+ " s.intersection(t) или s & t | Возвращает новое множество, включающее элементы, присутствующие одновременно в множествах s и t |
\n",
+ " s.intersection_update(t) или s &= t | Оставляет во множестве s пересечение множеств s и t |
\n",
+ " s.isdisjoint(t) | Возвращает True, если множества s и t не имеют общих элементов |
\n",
+ " s.issubset(t) или s <= t | Возвращает True, если множество s эквивалентно множеству t или является его подмножеством; чтобы проверить, является ли множество s только подмножеством множества t, следует использовать проверку s < t |
\n",
+ " s.issuperset(t) или s >= t | Возвращает True, если множество s эквивалентно множеству t или является его надмножеством; чтобы проверить, является ли множество s только надмножеством множества t, следует использовать проверку s > t |
\n",
+ " s.pop() | Возвращает и удаляет случайный элемент множества s или возбуждает исключение KeyError, если s – это пустое множество |
\n",
+ " s.remove(x) | Удаляет элемент x из множества s или возбуждает исключение KeyError, если элемент x отсутствует в множестве s |
\n",
+ " s.symmetric_difference(t) или s ^ t | Возвращает новое множество, включающее все элементы, присутствующие в множествах s и t, за исключением элементов, присутствующих в обоих множествах одновременно |
\n",
+ " s.symmetric_difference_update(t) или s ^= t | Возвращает в множестве s результат строгой дизъюнкции множеств s и t |
\n",
+ " s.union(t) или s | t | Возвращает новое множество, включающее все элементы множества s и все элементы множества t, отсутствующие в множестве s |
\n",
+ " s.update(t) или s |= t | Добавляет во множество s все элементы множества t, отсутствующие в множестве s |
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "\n",
+ "### Генераторы множеств\n",
+ "\n",
+ "\n",
+ "\n",
+ "В дополнение к возможности создавать множества с помощью функции\n",
+ "`set()` или литералов, существует возможность создавать множества с\n",
+ "помощью *генераторов множеств*. Генератор множества – это выражение и\n",
+ "цикл с необязательным условием, заключенные в фигурные скобки. Подобно\n",
+ "генераторам списков, генераторы множеств поддерживают две формы\n",
+ "записи:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```Python\n",
+ " {expression for item in iterable}\n",
+ " {expression for item in iterable if condition}\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Мы могли бы использовать генераторы множеств для фильтрации\n",
+ "нежелательных элементов (когда порядок следования элементов не имеет\n",
+ "значения), как показано ниже:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "html = {x for x in files if x.lower().endswith((\".htm\", \".html\"))}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Если предположить, что `files` – это список имен файлов, то данный\n",
+ "генератор множества создает множество `html`, в котором хранятся\n",
+ "только имена файлов с расширениями `.htm` и `.html`, независимо от\n",
+ "регистра символов.\n",
+ "\n",
+ "Как и в случае с генераторами списков, в генераторах множеств\n",
+ "используются итерируемые объеты, которые в свою очередь могут быть\n",
+ "генераторами множеств (или генераторами любого другого типа), что\n",
+ "позволяет создавать весьма замысловатые генераторы множеств.\n",
+ "\n",
+ "## Тип `frozenset`\n",
+ "\n",
+ "\n",
+ "Фиксированное множество (`frozenset`) – это множество, которое после\n",
+ "создания невозможно изменить. Хотя при этом мы, конечно, можем\n",
+ "повторно связать переменную, которая ссылалась на фиксированное\n",
+ "множество, с чем-то другим. Фиксированные множества могут создаваться\n",
+ "только в результате обращения к имени типа `frozenset` как к\n",
+ "функции. При вызове `frozenset()` без аргументов возвращается пустое\n",
+ "фиксированное множество; с аргументом типа `frozenset` возвращается\n",
+ "поверхностная копия аргумента; если аргумент имеет другой тип,\n",
+ "выполняется попытка преобразовать его в объект типа `frozenset`. Эта\n",
+ "функция принимает не более одного аргумента.\n",
+ "\n",
+ "Поскольку фиксированные множества относятся к категории неизменяемых\n",
+ "объектов, они поддерживают только те методы и операторы, которые\n",
+ "воспроизводят результат, не оказывая воздействия на фиксированное\n",
+ "множество или на множества, к которым они применяются.\n",
+ "\n",
+ "Поскольку фиксированные множества относятся к категории неизменяемых\n",
+ "объектов, они поддерживают только те методы и операторы, которые\n",
+ "воспроизводят результат, не оказывая воздействия на фиксированное\n",
+ "множество или на множества, к которым они применяются. \n",
+ "В табл. [collections:sets:tbl:1](#collections:sets:tbl:1) перечислены все методы множеств из\n",
+ "которых фиксированными множествами поддерживаются: `frozenset.copy()`,\n",
+ "`frozenset.difference()` (`-`), `frozenset.intersection()` (`&`),\n",
+ "`frozenset.isdis-joint()`, `frozenset.issubset()` (`<=` и `<` для\n",
+ "выявления подмножеств), `frozenset.issuperset()` (`>=` и `>` для\n",
+ "выявления надмножеств), `frozenset.union()` (`|`) и\n",
+ "`frozenset.symmetric_difference()` (`^`).\n",
+ "\n",
+ "Если двухместный оператор применяется ко множеству и фиксированному\n",
+ "множеству, тип результата будет совпадать с типом операнда, стоящего\n",
+ "слева от оператора. То есть если предположить, что `f` – это\n",
+ "фиксированное множество, а `s` – это обычное множество, то выражение\n",
+ "`f & s` вернет объект типа frozenset, а выражение `s & f` – объект\n",
+ "типа `set`. В случае операторов `==` и `!=` порядок операндов не имеет\n",
+ "значения, и выражение `f == s` вернет `True`, только если оба\n",
+ "множества содержат одни и те же элементы.\n",
+ "\n",
+ "Другое следствие неизменности фиксированных множеств заключается в\n",
+ "том, что они соответствуют критерию хеширования, предъявляемому к\n",
+ "элементам множеств, и потому множества и фиксированные множества могут\n",
+ "содержать другие фиксированные множества.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "# Отображения\n",
+ "\n",
+ "\n",
+ "Отображениями называются типы данных, поддерживающие оператор проверки\n",
+ "на вхождение (`in`), функцию `len()` и возможность обхода элементов в\n",
+ "цикле. Отображения – это коллекции пар элементов «ключ-значение»,\n",
+ "которые предоставляют методы доступа к элементам и их ключам и\n",
+ "значениям. При выполнении итераций порядок следования элементов\n",
+ "отображений может быть произвольным. В языке Python имеется два типа\n",
+ "отображений: встроенный тип `dict` и тип `collections.defaultdict`,\n",
+ "определяемый в стандартной библиотеке. Мы будем использовать термин\n",
+ "словарь для ссылки на любой из этих типов, когда различия между ними\n",
+ "не будут иметь никакого значения."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "import collections.defaultdict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "В качестве ключей словарей могут использоваться только хешируемые\n",
+ "объекты, поэтому в качестве ключей словаря такие неизменяемые типы,\n",
+ "как `float`, `frozenset`, `int`, `str` и `tuple`, использовать\n",
+ "допускается, а изменяемые типы, такие как `dict`, `list` и `set`, –\n",
+ "нет. С другой стороны, каждому ключу соответствует некоторое значение,\n",
+ "которое может быть ссылкой на объект любого типа, включая числа,\n",
+ "строки, списки, множества, словари, функции и т. д.\n",
+ "\n",
+ "Словари могут сравниваться с помощью стандартных операторов сравнения\n",
+ "(`<`, `<=`, `==`, `!=`, `>=`, `>`), при этом сравнивание производится\n",
+ "поэлементно (и рекурсивно, при наличии вложенных элементов, таких как\n",
+ "кортежи или словари в словарях). Пожалуй, единственными операторами\n",
+ "сравнения, применение которых к словарям имеет смысл, являются\n",
+ "операторы `==` и `!=`.\n",
+ "\n",
+ "## Словари\n",
+ "\n",
+ "\n",
+ "Тип `dict` – это неупорядоченная коллекция из нуля или более пар\n",
+ "«ключ-значение», в которых в качестве ключей могут использоваться\n",
+ "ссылки на хешируемые объекты, а в качестве значений – ссылки на\n",
+ "объекты любого типа. Словари относятся к категории изменяемых типов,\n",
+ "поэтому легко можно добавлять и удалять их элементы, но так как они\n",
+ "являются неупорядоченными коллекциями, к ним не применимо понятие\n",
+ "индекса и не применима операция извлечения среза.\n",
+ "\n",
+ "Тип данных `dict` может вызываться как функция `dict()` – без\n",
+ "аргументов она возвращает пустой словарь; если в качестве аргумента\n",
+ "передается отображение, возвращается словарь, основанный на этом\n",
+ "отображении: например, с аргументом типа `dict` возвращается\n",
+ "поверхностная копия словаря. Существует возможность передавать в\n",
+ "качестве аргумента последовательности, если каждый элемент\n",
+ "последовательности в свою очередь является последовательностью из двух\n",
+ "объектов, первый из которых используется в качестве ключа, а второй –\n",
+ "в качестве значения. Как вариант, для создания словарей, в которых \n",
+ "ключи являются допустимыми идентификаторами языка Python, можно\n",
+ "использовать именованные аргументы; тогда имена аргументов будут\n",
+ "играть роль ключей, а значения аргументов – роль значений\n",
+ "ключей. Кроме того, словари могут создаваться с помощью фигурных\n",
+ "скобок – пустые скобки `{}` создадут пустой словарь. Непустые фигурные\n",
+ "скобки должны содержать один или более элементов, разделенных\n",
+ "запятыми, каждый из которых состоит из ключа, символа двоеточия и\n",
+ "значения. Еще один способ создания словарей заключается в\n",
+ "использовании генераторов словарей – эта тема будет рассматриваться\n",
+ "ниже, в соответствующем подразделе.\n",
+ "\n",
+ "Ниже приводятся несколько способов создания словарей – все они создают\n",
+ "один и тот же словарь:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "d1 = dict({\"id\": 1948, \"name\": \"Washer\", \"size\": 3})\n",
+ "d2 = dict(id=1948, name=\"Washer\", size=3)\n",
+ "d3 = dict([(\"id\", 1948), (\"name\", \"Washer\"), (\"size\", 3)])\n",
+ "d4 = dict(zip((\"id\", \"name\", \"size\"), (1948, \"Washer\", 3)))\n",
+ "d5 = {\"id\": 1948, \"name\": \"Washer\", \"size\": 3}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "На рис. [collections:maps:fig:1](#collections:maps:fig:1) демонстрируется словарь, созданный\n",
+ "следующим фрагментом программного кода:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "d = {\"root\": 18, \"blue\": [75, \"R\", 2], 21: \"venus\", -14: None,\n",
+ " \"mars\": \"rover\", (4, 11): 18, 0: 45}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Ключи словарей являются уникальными, поэтому если в словарь\n",
+ "добавляется пара «ключ-значение» с ключом, который уже присутствует в\n",
+ "словаре, в результате происходит замена значения существующего ключа\n",
+ "новым значением. Для доступа к отдельным элементам используются\n",
+ "квадратные скобки: например, выражение `d[\"root\"]` вернет `18`,\n",
+ "выражение `d[21]` вернет строку `\"venus\"`, а выражение `d[91]` \n",
+ "применительно к словарю, изображенному на\n",
+ "рис. [collections:maps:fig:1](#collections:maps:fig:1), возбудит исключение `KeyError`. \n",
+ "\n",
+ "Квадратные скобки могут также использоваться для добавления и удаления\n",
+ "элементов словаря. Чтобы добавить новый элемент, используется оператор\n",
+ "`=`, например, `d[\"X\"] = 59`. Для удаления элементов используется\n",
+ "инструкция `del`, например, инструкция `del d[\"mars\"]` удалит из \n",
+ "словаря элемент с ключом `\"mars\"` или возбудит исключение `KeyError`,\n",
+ "если элемент с указанным ключом отсутствует в словаре. Кроме того,\n",
+ "элементы могут удаляться (и возвращаться вызывающей программе)\n",
+ "методом `dict.pop()`.\n",
+ "\n",
+ "Словари поддерживают встроенную функцию `len()` и для ключей\n",
+ "поддерживают возможность быстрой проверки на вхождение с помощью\n",
+ "операторов `in` и `not in`. В табл. [collections:maps:tbl:1](#collections:maps:tbl:1)\n",
+ "перечислены все методы словарей.\n",
+ "\n",
+ "Так как словари содержат пары «ключ-значение», у нас может возникнуть\n",
+ "потребность обойти в цикле элементы словаря (ключ, значение) по\n",
+ "значениям или по ключам. Например, ниже приводятся два эквивалентных\n",
+ "способа обхода пар «ключ-значение»:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "3\n",
+ "8\n",
+ " \n",
+ "<\n",
+ "<\n",
+ "<\n",
+ "!\n",
+ "!\n",
+ "C\n",
+ "O\n",
+ "D\n",
+ "E\n",
+ "_\n",
+ "B\n",
+ "L\n",
+ "O\n",
+ "C\n",
+ "K\n",
+ " \n",
+ " \n",
+ "p\n",
+ "y\n",
+ "c\n",
+ "o\n",
+ "d"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "for key, value in d.items():\n",
+ " print(key, value)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Таблица 3 : Методы словарей \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "| Синтаксис | Описание |
\n",
+ "\n",
+ "\n",
+ " d.clear() | Удаляет все элементы из словаря d |
\n",
+ " d.copy() | Возвращает поверхностную копию словаря d |
\n",
+ " d.fromkeys(s, v) | Возвращает словарь типа dict, ключами которого являются элементы последовательности s значениями либо None либо v, если аргумент v определен |
\n",
+ " d.get(k) | Возвращает значение ключа k или None, если ключ k отсутствует в словаре |
\n",
+ " d.get(k, v) | Возвращает значение ключа k или v, если ключ k отсутствует в словаре |
\n",
+ " d.items() | Возвращает представление всех пар (ключ, значение) в словаре d |
\n",
+ " d.keys() | Возвращает представление всех ключей словаря d |
\n",
+ " d.pop(k) | Возвращает значение ключа k и удаляет из словаря элемент с ключом k или возбуждает исключение KeyError, если ключ k отсутствует в словаре |
\n",
+ " d.pop(k, v) | Возвращает значение ключа k и удаляет из словаря элемент с ключом k или возвращает значение v, если ключ k отсутствует в словаре |
\n",
+ " d.popitem() | Возвращает и удаляет произвольную пару (ключ, значение) из словаря d или возбуждает исключение KeyError, если словарь d пуст |
\n",
+ " d.setdefault(k, v) | То же что и dict.get() за исключением того, что, если ключ k в словаре отсутствует, в словарь вставляется новый элемент с ключом k и со значением None или v, если аргумент v задан |
\n",
+ " d.update(a) | Добавляет в словарь d пары (ключ, значение) из a, которые отсутствуют в словаре d а для каждого ключа который уже присутствует в словаре d выполняется замена соответствующим значением из a; a может быть словарем итерируемым объектом с парами (ключ значение) или именованными аргументами |
\n",
+ " d.values() | Возвращает представление всех значений в словаре d |
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "\n",
+ "\n",
+ "Обход значений в словаре выполняется похожим способом:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "for value in d.values():\n",
+ " print(value)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Для обхода ключей в словаре можно использовать метод `dict.keys()`\n",
+ "или просто интерпретировать словарь как итерируемый объект и вы-\n",
+ "полнить итерации по его ключам, как показано в следующих двух\n",
+ "фрагментах:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "for key in d:\n",
+ " print(key)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "for key in d.keys():\n",
+ " print(key)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Если необходимо изменить значения в словаре, то можно выполнить\n",
+ "обход ключей словаря в цикле и изменить значения, используя оператор\n",
+ "квадратных скобок. Например, ниже показано, как можно было бы\n",
+ "увеличить все значения в словаре `d`, если предполагать, что все\n",
+ "значения являются числами:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "for key in d:\n",
+ " d[key] += 1"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Методы `dict.items()`, `dict.keys()` и `dict.values()` возвращают\n",
+ "представления словарей. Представление словаря – это в действительности\n",
+ "итерируемый объект, доступный только для чтения и хранящий элементы,\n",
+ "ключи или значения словаря в зависимости от того, какое представление\n",
+ "было запрошено.\n",
+ "\n",
+ "### Генераторы словарей\n",
+ "\n",
+ "\n",
+ "\n",
+ "*Генератор словарей* – это выражение и цикл с необязательным условием,\n",
+ "заключенное в фигурные скобки, очень напоминающее генератор\n",
+ "множеств. Подобно генераторам списков и множеств, генераторы словарей\n",
+ "поддерживают две формы записи:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```Python\n",
+ " {keyexpression: valueexpression for key, value in iterable}\n",
+ " {keyexpression: valueexpression for key, value in iterable if condition}\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Ниже показано, как можно использовать генератор словарей для создания\n",
+ "словаря, в котором каждый ключ является именем файла в текущем\n",
+ "каталоге, а каждое значение – это размер файла в байтах:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```Python\n",
+ " file_sizes = {name: os.path.getsize(name) for name in os.listdir(\".\")}\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Функция `os.listdir()` из модуля os («operating system» – операционная\n",
+ "система) возвращает список файлов и каталогов в указанном каталоге, но\n",
+ "при этом в список никогда не включаются специальные имена каталогов\n",
+ "«.» или «..». Функция os.path.getsize() возвращает размер заданного\n",
+ "файла в байтах. Чтобы отфильтровать каталоги и другие элементы списка,\n",
+ "не являющиеся файлами, можно добавить дополнительное условие:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```Python\n",
+ " file_sizes = {name: os.path.getsize(name) for name in os.listdir(\".\")\n",
+ " \t if os.path.isfile(name)}\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Функция `os.path.isfile()` из модуля `os.path` возвращает `True`, если\n",
+ "указанный путь соответствует файлу, и `False` – в противном случае, то\n",
+ "есть для каталогов, ссылок и тому подобного.\n",
+ "\n",
+ "Генераторы словарей могут также использоваться для создания инвер-\n",
+ "тированных словарей. Например, пусть имеется словарь `d`, тогда мы\n",
+ "можем создать новый словарь, ключами которого будут значения словаря\n",
+ "`d`, а значениями – ключи словаря `d`:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```Python\n",
+ " inverted_d = {v: k for k, v in d.items()}\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Полученный словарь можно инвертировать обратно и получить\n",
+ "первоначальный словарь – при условии, что все значения в\n",
+ "первоначальном словаре были уникальными, однако инверсия будет терпеть\n",
+ "неудачу, с возбуждением исключения `TypeError`, если какое-либо\n",
+ "значение окажется не хешируемым.\n",
+ "\n",
+ "\n",
+ "## Словари со значениями по умолчанию\n",
+ "\n",
+ "\n",
+ "Словари со значениями по умолчанию – это обычные словари, они\n",
+ "поддерживают те же самые методы и операторы, что и обычные\n",
+ "словари. Единственное, что отличает такие словари от обычных словарей,\n",
+ "– это способ обработки отсутствующих ключей, но во всех остальных\n",
+ "отношениях они ничем не отличаются друг от друга. \n",
+ "\n",
+ "При обращении к несуществующему («отсутствующему») ключу слова-\n",
+ "ря возбуждается исключение `KeyError`. Это очень удобно, так как\n",
+ "нередко для нас бывает желательно знать об отсутствии ключа, который,\n",
+ "согласно нашим предположениям, может присутствовать. Но в некоторых\n",
+ "случаях бывает необходимо, чтобы в словаре присутствовали все ключи,\n",
+ "которые мы используем, даже если это означает, что элемент с заданным\n",
+ "ключом добавляется в словарь в момент первого обращения к нему.\n",
+ "\n",
+ "Например, допустим, что имеется словарь `d`, который не имеет элемента\n",
+ "с ключом m, тогда выражение `x = d[m]` возбудит исключение\n",
+ "`KeyError`. Если `d` – это словарь со значениями по умолчанию,\n",
+ "созданный соответствующим способом, а элемент с ключом m принадлежит\n",
+ "такому словарю, то при обращении к нему будет возвращено\n",
+ "соответствующее значение, как и в случае с обычным словарем. Но если в\n",
+ "словаре со значениями по умолчанию отсутствует ключ m, то будет создан\n",
+ "новый элемент словаря с ключом m и со значением по умолчанию, и будет\n",
+ "возвращено значение этого, вновь созданного элемента. \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "# Обход в цикле и копирование коллекций\n",
+ "\n",
+ "\n",
+ "После того как будет создана коллекция элементов данных, вполне\n",
+ "естественно возникает желание обойти все элементы, содержащиеся в\n",
+ "ней. Еще одна часто выполняемая операция – копирование коллекций. Из-за\n",
+ "того, что в языке Python повсеместно используются ссылки на объекты\n",
+ "(ради повышения эффективности), существуют некоторые особенности,\n",
+ "связанные с копированием.\n",
+ "\n",
+ "В этом разделе сначала мы рассмотрим итераторы языка Python, а затем\n",
+ "принципы копирования коллекций.\n",
+ "\n",
+ "## Итераторы, функции и операторы для работы с итерируемыми объектами\n",
+ "\n",
+ "\n",
+ "*Итерируемый* тип данных – это такой тип, который может возвращать\n",
+ "свои элементы по одному. Любой объект, имеющий метод `__iter__()`, или\n",
+ "любая последовательность (то есть объект, имеющий метод\n",
+ "`__getitem__()`, принимающий целочисленный аргумент со значением от\n",
+ "`0` и выше), является итерируемым и может предоставлять\n",
+ "итератор. Итератор – это объект, имеющий метод `__next__()`, который\n",
+ "при каждом вызове возвращает очередной элемент и возбуждает исключение\n",
+ "`StopIteration` после исчерпания всех элементов. В\n",
+ "табл. [collections:iterandcopy:iterator:tbl:1](#collections:iterandcopy:iterator:tbl:1) перечислены\n",
+ "операторы и функции, которые могут применяться к итерируемым\n",
+ "объектам. \n",
+ "\n",
+ "\n",
+ "## Таблица 4 : Общие функции и операторы для работы с итерируемыми объектами \n",
+ "\n",
+ "\n",
+ "\n",
+ "| Синтаксис | Описание |
\n",
+ "\n",
+ "\n",
+ " s + t | Возвращает конкатенацию последовательностей s и t |
\n",
+ " s * n | Возвращает конкатенацию из int n последовательностей s |
\n",
+ " x in i | Возвращает True, если элемент x присутствует в итерируемом объекте i, обратная проверка выполняется с помощью оператора not in |
\n",
+ " all(i) | Возвращает True, если все элементы итерируемого объекта i в логическом контексте оцениваются как значение True |
\n",
+ " any(i) | Возвращает True, если хотя бы один элемент итерируемого объекта i в логическом контексте оценивается как значение True |
\n",
+ " enumerate (i,start) | Обычно используется в циклах for ... in, чтобы получить последовательность кортежей (index, item), где значения индексов начинают отсчитывать от 0 или от значения start |
\n",
+ " len(x) | Возвращает «длину» объекта x. Если x – коллекция, то возвращаемое число представляет количество элементов. Если x – строка, то возвращаемое число представляет количество символов |
\n",
+ " max(i, key) | Возвращает наибольший элемент в итерируемом объекте i или элемент с наибольшим значением key(item), если функция key определена |
\n",
+ " min(i, key) | Возвращает наименьший элемент в итерируемом объекте i или элемент с наименьшим значением key(item), если функция key определена |
\n",
+ " range(start, stop, step) | Возвращает целочисленный итератор. С одним аргументом (stop) итератор представляет последовательность целых чисел от 0 до stop-1, с двумя аргументами (start, stop) – последовательность целых чисел от start до stop-1, с тремя аргументами – последовательность целых чисел от start до stop-1 c шагом step |
\n",
+ " reversed(i) | Возвращает итератор, который будет возвращать элементы итератора i в обратном порядке |
\n",
+ " sorted(i, key, reverse) | Возвращает список элементов итератора i в отсортированном порядке. Аргумент key используется для выполнения сортировки DSU (Decorate, Sort, Undecorate – декорирование, сортировка, обратное декорирование). Если аргумент reverse имеет значение True, сортировка выполняется в обратном порядке |
\n",
+ " sum(i, start) | Возвращает сумму элементов итерируемого объекта i, плюс ар гумент start (значение которого по умолчанию равно 0). Объект i не должен содержать строк |
\n",
+ " zip(i1, ..., iN) | Возвращает итератор кортежей, используя итераторы от i1 до iN |
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "\n",
+ "Порядок, в котором возвращаются элементы, зависит от итерируемого\n",
+ "объекта. В случае списков и кортежей элементы обычно возвращаются\n",
+ "в предопределенном порядке, начиная с первого элемента (находящегося в\n",
+ "позиции с индексом `0`), но другие итераторы возвращают элементы в\n",
+ "произвольном порядке – например, итераторы словарей и множеств.\n",
+ "\n",
+ "Встроенная функция `iter()` используется двумя совершенно различными\n",
+ "способами. Применяемая к коллекции или к последовательности, она\n",
+ "возвращает итератор для заданного объекта или возбуждает исключение\n",
+ "`TypeError`, если объект не является итерируемым. Такой способ часто\n",
+ "используется при работе с нестандартными типами коллекций \n",
+ "и крайне редко – в других контекстах. Во втором варианте использования\n",
+ "функции `iter()` ей передается вызываемый объект (функция или метод) и\n",
+ "специальное значение. В этом случае полученная функция или метод\n",
+ "вызывается на каждой итерации, а значение этой функции, если оно не\n",
+ "равно специальному значению, возвращается вызывающей программе; в\n",
+ "противном случае возбуждается исключение `StopIteration`.\n",
+ "\n",
+ "Когда в программе используется цикл `for item in iterable`,\n",
+ "интерпретатор Python вызывает функцию `iter(iterable)`, чтобы получить\n",
+ "итератор. После этого на каждой итерации вызывается метод `__next__()`\n",
+ "итератора, чтобы получить очередной элемент, а когда возбуждается\n",
+ "исключение `StopIteration`, оно перехватывается и цикл завершается.\n",
+ "Другой способ получить очередной элемент итератора состоит в том,\n",
+ "чтобы вызвать встроенную функцию `next()`. Ниже приводятся два\n",
+ "эквивалентных фрагмента программного кода (оба они вычисляют\n",
+ "произведение элементов списка), в одном из них используется цикл\n",
+ "`for ... in`, а во втором явно используется итератор:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "product = 1\n",
+ "for i in [1, 2, 4, 8]:\n",
+ " product *= i\n",
+ "print(product)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "product = 1\n",
+ "i = iter([1, 2, 4, 8])\n",
+ "while True:\n",
+ " try:\n",
+ " product *= next(i)\n",
+ " except StopIteration:\n",
+ " break\n",
+ "print(product)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Любой (конечный) итерируемый объект `i` может быть преобразован\n",
+ "в кортеж вызовом функции `tuple(i)` или в список – вызовом функции\n",
+ "`list(i)`.\n",
+ "\n",
+ "## Копирование коллекций\n",
+ "\n",
+ "\n",
+ "Поскольку в языке Python повсюду используются ссылки на объекты, когда\n",
+ "выполняется оператор присваивания (`=`), никакого копирования данных\n",
+ "на самом деле не происходит. Если справа от оператора находится\n",
+ "литерал, например, строка или число, в операнд слева записывается\n",
+ "ссылка, которая указывает на объект в памяти, хранящий значение\n",
+ "литерала. Если справа находится ссылка на объект, в левый операнд\n",
+ "записывается ссылка, указывающая на тот же самый объект, на который\n",
+ "ссылается правый операнд. Вследствие этого операция присваивания\n",
+ "обладает чрезвычайно высокой скоростью выполнения. \n",
+ "\n",
+ "Когда выполняется присваивание крупной коллекции, такой как\n",
+ "длинный список, экономия времени становится более чем очевидной.\n",
+ "Например:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "songs = [\"Because\", \"Boys\", \"Carol\"]\n",
+ "beatles = songs\n",
+ "beatles, songs"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Здесь была создана новая ссылка на объект (`beatles`), и обе ссылки\n",
+ "указывают на один и тот же список – никакого копирования данных не\n",
+ "производилось. \n",
+ "\n",
+ "Поскольку списки относятся к категории изменяемых объектов, мы\n",
+ "можем вносить в них изменения. Например:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "beatles[2] = \"Cayenne\"\n",
+ "beatles, songs"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Изменения были внесены с использованием переменной `beatles`, но это\n",
+ "всего лишь ссылка, указывающая на тот же самый объект, что и ссылка\n",
+ "songs. Поэтому любые изменения, произведенные с использованием одной\n",
+ "ссылки, можно наблюдать с использованием другой ссылки. \n",
+ "Часто это именно то, что нам требуется, поскольку копирование крупных\n",
+ "коллекций может оказаться дорогостоящей операцией. Кроме того, это\n",
+ "также означает, что имеется возможность передавать списки или другие\n",
+ "изменяемые коллекции в виде аргументов функций, изменять эти коллекции\n",
+ "в функциях и пребывать в уверенности, что изменения будут доступны\n",
+ "после того, как функция вернет управление вызывающей программе. \n",
+ "\n",
+ "Однако в некоторых ситуациях действительно бывает необходимо создать\n",
+ "отдельную копию коллекции (то есть создать другой изменяемый\n",
+ "объект). В случае последовательностей, когда выполняется оператор\n",
+ "извлечения среза, например, `songs[:2]`, полученный срез – это всегда \n",
+ "независимая копия элементов. Поэтому скопировать последовательность\n",
+ "целиком можно следующим способом:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "songs = [\"Because\", \"Boys\", \"Carol\"]\n",
+ "beatles = songs[:]\n",
+ "beatles[2] = \"Cayenne\"\n",
+ "beatles, songs"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "В случае словарей и множеств копирование можно выполнить с помощью\n",
+ "методов `dict.copy()` и `set.copy()`. Кроме того, в модуле copy\n",
+ "имеется функция copy.copy(), которая возвращает копию заданного\n",
+ "объекта. Другой способ копирования встроенных типов коллекций\n",
+ "заключается в использовании имени типа как функции, которой в качестве\n",
+ "аргумента передается копируемая коллекция. Например:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "copy_of_dict_d = dict(d)\n",
+ "copy_of_list_L = list(L)\n",
+ "copy_of_set_s = set(s)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Обратите внимание, что все эти приемы копирования\n",
+ "создают *поверхностные копии*, то есть копируются только ссылки на\n",
+ "объекты, но не сами объекты. Для неизменяемых типов данных, таких как числа\n",
+ "и строки, это равносильно копированию (за исключением более высокой\n",
+ "эффективности), но для изменяемых типов данных, таких как вложенные\n",
+ "коллекции, это означает, что ссылки в оригинальной коллекции и в копии\n",
+ "будут указывать на одни и те же объекты. Эту особенность иллюстрирует\n",
+ "следующий пример:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "x = [53, 68, [\"A\", \"B\", \"C\"]]\n",
+ "y = x[:] # поверхностное копирование\n",
+ "x, y"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "y[1] = 40\n",
+ "x[2][0] = 'Q'\n",
+ "x, y"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Когда выполняется поверхностное копирование списка `x`, копируется\n",
+ "ссылка на вложенный список `[\"A\", \"B\", \"C\"]`. Это означает, что третий\n",
+ "элемент в обоих списках, `x` и `y`, ссылается на один и тот же список,\n",
+ "поэтому любые изменения, произведенные во вложенном списке, можно\n",
+ "наблюдать с помощью любой из ссылок, `x` или `y`. Если действительно\n",
+ "необходимо создать абсолютно независимую копию коллекции с\n",
+ "произвольной глубиной вложенности, необходимо выполнить глубокое \n",
+ "копирование:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "import copy\n",
+ "x = [53, 68, [\"A\", \"B\", \"C\"]]\n",
+ "y = copy.deepcopy(x)\n",
+ "y[1] = 40\n",
+ "x[2][0] = 'Q'\n",
+ "x, y"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Здесь списки `x` и `y`, а также элементы, которые они содержат,\n",
+ "полностью независимы. \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ ""
+ ]
+ }
+ ],
+ "metadata": {},
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/datatype.ipynb b/datatype.ipynb
index b3fff2f..b5c5907 100644
--- a/datatype.ipynb
+++ b/datatype.ipynb
@@ -10,15 +10,13 @@
" \n",
"**С.В. Лемешевский** (email: `sergey.lemeshevsky@gmail.com`), Институт математики НАН Беларуси\n",
"\n",
- "Date: **Feb 24, 2020**\n",
+ "Date: **Feb 27, 2020**\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
- "\n",
- "\n",
"Здесь разберем как Python работает с переменными и определим, какие\n",
"типы данных можно использовать в рамках этого языка. Подробно рассмотрим модель\n",
"данных Python, а также механизмы создания и изменения значения\n",
@@ -1514,7 +1512,7 @@
"Как показано в примере, мы можем также использовать комбинированный\n",
"оператор присваивания с дублированием. \n",
"\n",
- "# Форматирование строк с помощью метода `str.format()`\n",
+ "## Форматирование строк с помощью метода `str.format()`\n",
"\n",
"\n",
"Метод `str.format()` представляет собой очень мощное и гибкое средство\n",
@@ -1608,6 +1606,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "В следующем разделе мы рассмотрим применение функции `str.format()`.\n",
+ "\n",
"\n",
"\n",
"\n",
@@ -1615,8 +1615,195 @@
"# Примеры\n",
"\n",
"\n",
+ "## Печать символов Юникода\n",
+ "\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",
"## `quadratic.py`\n",
@@ -1658,17 +1845,701 @@
"С коэффициентами $1.5$, $-3$ и $6$ программа выведет (некоторые цифры\n",
"обрезаны):\n",
"\n",
+ "Теперь обратимся к программному коду, который начинается тремя инструкциями `import`:\n",
+ "\n",
+ "Нам необходимы обе математические библиотеки для работы с числами типа\n",
+ "`float` и `complex`, так как функции, вычисляющие квадратный \n",
+ "корень из вещественных и комплексных чисел, отличаются. Модуль\n",
+ "`sys` нам необходим, так как в нем определена константа\n",
+ "`sys.float_info.epsilon`, которая потребуется нам для сравнения\n",
+ "вещественных чисел со значением `0`.\n",
+ "\n",
+ "Нам также необходима функция, которая будет получать от пользова-\n",
+ "теля число с плавающей точкой:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "# Start get_float\n",
+ "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": 55,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "# Start 1st block\n",
+ "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": 56,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "# Start 2d block\n",
+ "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": 57,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "# Start 3d block\n",
+ "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",
+ "## `csv2html.py`\n",
+ "\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": [
+ "Предположим, что данные находятся в файле\n",
+ "\"sample.csv\": \"src-datatype/sample.csv\" и выполнена комадна"
+ ]
+ },
+ {
+ "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": [
+ " \n",
+ " \n",
+ " | \"Country\" | \n",
+ " 2000 | \n",
+ " 2001 | \n",
+ " 2002 | \n",
+ " 2003 | \n",
+ " 2004 | \n",
+ "
\n",
+ " \n",
+ " | \"Antigua and Barbuda\" | \n",
+ " 0 | \n",
+ " 0 | \n",
+ " 0 | \n",
+ " 0 | \n",
+ " 0 | \n",
+ "
\n",
+ " \n",
+ " | \"Argentina\" | \n",
+ " 37 | \n",
+ " 35 | \n",
+ " 33 | \n",
+ " 36 | \n",
+ " 39 | \n",
+ "
\n",
+ " \n",
+ " | \"Bahamas, The\" | \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | \"Bahrain\" | \n",
+ " 5 | \n",
+ " 6 | \n",
+ " 6 | \n",
+ " 6 | \n",
+ " 6 | \n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "На рис. показано, как выглядит полученная таблица в веб-броузере.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "Теперь, когда мы увидели, как используется программа и что она делает,\n",
+ "можно приступать к изучению программного кода.\n",
+ "\n",
+ "Последняя инструкция в программе – это простой вызов функции:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 58,
+ "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` первой вызываемой функцией является функция\n",
+ "`main()`, которая в свою очередь вызывает функции `print_start()` и\n",
+ "`print_line()`. Функция `print_line()` вызывает функции\n",
+ "`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": 59,
+ "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": 60,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "def print_start():\n",
+ " print(\"\")\n",
+ "\n",
+ "def print_end():\n",
+ " print(\"
\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Мы могли бы не создавать эти две функции и просто вставить\n",
+ "соответствующие вызовы `print()` в функцию `main()`. Но мы предпочитаем\n",
+ "выделять логику, так как это делает реализацию более гибкой, хотя\n",
+ "в этом маленьком примере гибкость не имеет большого значения."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 61,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "def print_line(line, color, maxwidth):\n",
+ " print(\"\".format(color))\n",
+ " fields = extract_fields(line)\n",
+ " for field in fields:\n",
+ " if not field:\n",
+ " print(\" | \")\n",
+ " else:\n",
+ " number = field.replace(\",\", \"\")\n",
+ " try:\n",
+ " x = float(number)\n",
+ " print(\"{0:d} | \".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(\"{0} | \".format(field))\n",
+ " else:\n",
+ " print(\"{0:.{1}} ... | \".format(field, maxwidth))\n",
+ " print(\"
\")"
+ ]
+ },
+ {
+ "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": 62,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "print(\"{0} ... | \".format(field[:maxwidth]))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Еще одно преимущество такого подхода состоит в том, что он требует\n",
+ "меньшего объема ввода с клавиатуры."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "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": 64,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "def escape_html(text):\n",
+ " text = text.replace(\"&\", \"&\")\n",
+ " text = text.replace(\"<\", \"<\")\n",
+ " text = text.replace(\">\", \">\")\n",
+ " return text"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Эта функция просто замещает каждый специальный символ HTML\n",
+ "соответствующей ему сущностью языка HTML. В первую очередь, конечно,\n",
+ "мы должны заменить символ амперсанда и угловые скобки, хотя порядок не\n",
+ "имеет никакого значения. \n",
+ "\n",
"\n",
"\n",
"\n",
"\n",
+ "# Упражнения\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "## Изменение вывода символов Юникода\n",
+ "\n",
+ "\n",
+ "Измените программу `print_unicode.py` так, чтобы пользователь мог\n",
+ "вводить в командной строке несколько разных слов и получать\n",
+ "только те строки из таблицы символов Юникода, в которых содержатся все\n",
+ "слова, указанные пользователем. Это означает, что мы сможем вводить\n",
+ "такие команды:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "print_unicode_ans.py greek symbol"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "**Подсказка.**\n",
+ "Один из способов достижения поставленной цели состоит в том,\n",
+ "чтобы заменить переменную `word` (которая может хранить `0`, `None` \n",
+ "или строку) списком `words`. Не забудьте изменить информацию о порядке\n",
+ "использования. В результате изменений не более десяти строк\n",
+ "программного кода добавится и не более десяти строк изменится.\n",
+ "\n",
+ "\n",
+ "Имя файла: `print_unicode_ans.py`.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "## Изменение `quadratic.py`\n",
+ "\n",
+ "\n",
+ "Измените программу `quadratic.py` так, чтобы она не выводила\n",
+ "коэффициенты со значением `0.0`, а отрицательные коэффициенты\n",
+ "выводились бы как `-n`, а не `+ - n`.\n",
+ "Имя файла: `quadratic_ans.py`.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "## Использование функции `escape()`\n",
+ "\n",
+ "\n",
+ "Удалите функцию `escape_html()` из программы `cvs2html.py` и\n",
+ "используйте вместо нее функцию `xml.sax.saxutils.escape()` из модуля \n",
+ "`xml.sax.saxutils`.\n",
+ "\n",
+ "\n",
+ "\n",
+ "**Подсказка.**\n",
+ "Для этого потребуется добавить одну новую строку\n",
+ "(с инструкцией `import`), удалить пять строк (с ненужной функцией)\n",
+ "и изменить одну строку (задействовать функцию\n",
+ "`xml.sax.saxutils.escape()` вместо `escape_html()`).\n",
+ "\n",
+ "\n",
+ "Имя файла: `cvs2html_ans1.py`.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "## Добавление обработки параметров командной строки в `csv2html.py`\n",
+ "\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": [
+ "\n",
+ "\n",
+ "**Подсказка.**\n",
+ "Не забудьте изменить функцию `print_line()` так, чтобы она\n",
+ "использовала переменную `format` при выводе чисел – для этого вам\n",
+ "придется передавать функции дополнительный аргумент, добавить одну \n",
+ "строку и изменить еще одну строку. И это немного затронет функцию\n",
+ "`main()`. Функция `process_options()` должна содержать порядка\n",
+ "двадцати пяти строк (включая девять строк с текстом сообщения о\n",
+ "порядке использования).\n",
+ "\n",
+ "\n",
+ "Имя файла: `cvs2html_ans2.py`.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
- ""
+ "\n",
+ ""
]
}
],
diff --git a/fig-collections/map_1.png b/fig-collections/map_1.png
new file mode 100644
index 0000000..c7c43ea
Binary files /dev/null and b/fig-collections/map_1.png differ
diff --git a/fig-collections/seq_1.png b/fig-collections/seq_1.png
new file mode 100644
index 0000000..ed06453
Binary files /dev/null and b/fig-collections/seq_1.png differ
diff --git a/fig-collections/seq_2.png b/fig-collections/seq_2.png
new file mode 100644
index 0000000..90d6f98
Binary files /dev/null and b/fig-collections/seq_2.png differ
diff --git a/fig-collections/set_1.png b/fig-collections/set_1.png
new file mode 100644
index 0000000..b45c11f
Binary files /dev/null and b/fig-collections/set_1.png differ
diff --git a/fig-collections/set_2.png b/fig-collections/set_2.png
new file mode 100644
index 0000000..bdef9eb
Binary files /dev/null and b/fig-collections/set_2.png differ
diff --git a/fig-datatype/example_1.png b/fig-datatype/example_1.png
new file mode 100644
index 0000000..4e14ad0
Binary files /dev/null and b/fig-datatype/example_1.png differ
diff --git a/intro.ipynb b/intro.ipynb
index 76b7326..15ff52a 100644
--- a/intro.ipynb
+++ b/intro.ipynb
@@ -10,15 +10,13 @@
" \n",
"**С.В. Лемешевский** (email: `sergey.lemeshevsky@gmail.com`), Институт математики НАН Беларуси\n",
"\n",
- "Date: **Feb 22, 2020**\n",
+ "Date: **Feb 26, 2020**\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
- "\n",
- "\n",
"# Установка\n",
"\n",
"\n",
@@ -1462,8 +1460,7 @@
"\n",
"\n",
"\n",
- "### Jupyter Notebook\n",
- "\n",
+ "## Jupyter Notebook\n",
"\n",
"\n",
"Кроме интерактивной консоли Jupyter также предоставляет веб-приложение\n",
@@ -1529,7 +1526,7 @@
"сохраняются в формате JSON со специальным разрешением `ipynb`. Файл\n",
"Jupyter Notebook не является чистым кодом на Python, но при\n",
"необходимости код на Python можно легко выделить из блокнота используя\n",
- "либо меню «File ➤ Download as ➤ Python» или с помощью утилиты\n",
+ "либо меню **File | Download as | Python** или с помощью утилиты\n",
"`nbconvert`.\n",
"\n",
"\n",
@@ -1581,8 +1578,6 @@
"\n",
"\n",
"\n",
- "\n",
- "\n",
"Используя меню и панель инструментов, ячейки можно добавлять,\n",
"удалять, перемещать вверх и вниз, вырезать и вставлять и т.д. Эти\n",
"функции также связаны с сочетаниями клавиш, которые удобны и\n",
@@ -1599,11 +1594,9 @@
"доступными через панель инструментов и меню. \n",
"\n",
"\n",
- "\n",
- "\n",
"\n",
+ "## Таблица 1 : Клавиши \n",
"\n",
- "**Таблица 1.** \n",
"\n",
"\n",
"\n",
@@ -1624,19 +1617,19 @@
" Enter | Войти в режим редактирования ячейки |
\n",
" Escape | Выйти из режима редактирования ячейки |
\n",
" Shift-Enter | Выполнить ячейку |
\n",
- " h | Показать окно помощи со списком сочиетаний клавиш |
\n",
+ " h | Показать окно помощи со списком сочетаний клавиш |
\n",
" 0-0 | Перезапустить ядро |
\n",
" i-i | Прервать выполнение ячейки |
\n",
" s | Сохранить блокнот |
\n",
"\n",
"
\n",
- "\n",
+ "\n",
"\n",
"Во время выполнения ячейки блокнота номер ячейки обозначается\n",
"звездочкой (`In [*]`), а индикатор в правом верхнем углу страницы\n",
"сигнализирует о том, что ядро IPython занято. Прервать выполнение\n",
- "ячейки можно через меню «Kernel ➤ Interrupt» или сочетанием клавиш\n",
- "`i-i` в командном режиме (т.е., дважды нажать клавишу `i`). В таблице 1\n",
+ "ячейки можно через меню **Kernel | Interrupt** или сочетанием клавиш\n",
+ "`i-i` в командном режиме (т.е., дважды нажать клавишу `i`). В таблице [table:1](#table:1)\n",
"представлены наиболее популярные сочетания клавиш командного режима\n",
"Jupyter Notebook.\n",
"\n",
@@ -2050,7 +2043,7 @@
"\n",
"Каждую панель можно настроить для отображения или скрытия в\n",
"зависимости от предпочтений и потребностей пользователя, используя\n",
- "меню «View ➤ Panes». \n",
+ "меню **View | Panes**.\n",
"\n",
"### Редактор исходного кода\n",
"\n",
@@ -2097,8 +2090,8 @@
"поскольку она позволяет исследовать значения переменных после\n",
"завершения выполнения сценария. Spyder поддерживает одновременное\n",
"открытие нескольких консолей Python и IPython, и, например, новую\n",
- "консоль IPython можно запустить через меню «Consoles ➤ Open an IPython\n",
- "console». При запуске сценария из редактора нажатием клавиши F5 или\n",
+ "консоль IPython можно запустить через меню **Consoles | Open an IPython\n",
+ "console**. При запуске сценария из редактора нажатием клавиши F5 или\n",
"кнопки запуска на панели инструментов сценарий по умолчанию\n",
"запускается в самой последней активированной консоли. Это позволяет\n",
"поддерживать разные консоли с независимыми пространствами имен для\n",
diff --git a/src-datatype/csv2html.py b/src-datatype/csv2html.py
new file mode 100644
index 0000000..6043b61
--- /dev/null
+++ b/src-datatype/csv2html.py
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+
+def main():
+ maxwidth = 100
+ print_start()
+ count = 0
+ while True:
+ try:
+ line = input()
+ if count == 0:
+ color = "lightgreen"
+ elif count % 2:
+ color = "white"
+ else:
+ color = "lightyellow"
+ print_line(line, color, maxwidth)
+ count += 1
+ except EOFError:
+ break
+ print_end()
+
+def print_start():
+ print("")
+
+def print_end():
+ print("
")
+
+def print_line(line, color, maxwidth):
+ print("".format(color))
+ fields = extract_fields(line)
+ for field in fields:
+ if not field:
+ print(" | ")
+ else:
+ number = field.replace(",", "")
+ try:
+ x = float(number)
+ print("{0:d} | ".format(round(x)))
+ except ValueError:
+ field = field.title()
+ field = field.replace(" And ", " and ")
+ field = escape_html(field)
+ if len(field) <= maxwidth:
+ print("{0} | ".format(field))
+ else:
+ print("{0:.{1}} ... | ".format(field, maxwidth))
+ print("
")
+
+def extract_fields(line):
+ fields = []
+ field = ""
+ quote = None
+ for c in line:
+ if c in "\"'":
+ if quote is None: # начало строки в кавычках
+ quote = c
+ elif quote == c: # конец строки в кавычках
+ quote = None
+ else:
+ field += c
+ # другая кавычка внутри строки в кавычках
+ continue
+ if quote is None and c == ",": # end of a field
+ fields.append(field)
+ field = ""
+ else:
+ field += c
+ # добавить символ в поле
+ if field:
+ fields.append(field) # добавить последнее поле в список
+ return fields
+
+def escape_html(text):
+ text = text.replace("&", "&")
+ text = text.replace("<", "<")
+ text = text.replace(">", ">")
+ return text
+
+
+main()
diff --git a/src-datatype/csv2html.py~ b/src-datatype/csv2html.py~
new file mode 100644
index 0000000..b4d4ce4
--- /dev/null
+++ b/src-datatype/csv2html.py~
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+
+def main():
+ maxwidth = 100
+ print_start()
+ count = 0
+ while True:
+ try:
+ line = input()
+ if count == 0:
+ color = "lightgreen"
+ elif count % 2:
+ color = "white"
+ else:
+ color = "lightyellow"
+ print_line(line, color, maxwidth)
+ count += 1
+ except EOFError:
+ break
+ print_end()
+
+def print_start():
+ print("")
+
+def print_end():
+ print("
")
+
+def print_line(line, color, maxwidth):
+ print("".format(color))
+ fields = extract_fields(line)
+ for field in fields:
+ if not field:
+ print(" | ")
+ else:
+ number = field.replace(",", "")
+ try:
+ x = float(number)
+ print("{0:d} | ".format(round(x)))
+ except ValueError:
+ field = field.title()
+ field = field.replace(" And ", " and ")
+ field = escape_html(field)
+ if len(field) <= maxwidth:
+ print("{0} | ".format(field))
+ else:
+ print("{0:.{1}} ... | ".format(field, maxwidth))
+ print("
")
+
+def extract_fields(line):
+ fields = []
+ field = ""
+ quote = None
+ for c in line:
+ if c in "\"'":
+ if quote is None: # начало строки в кавычках
+ quote = c
+ elif quote == c: # конец строки в кавычках
+ quote = None
+ else:
+ field += c
+ # другая кавычка внутри строки в кавычках
+ continue
+ if quote is None and c == ",": # end of a field
+ fields.append(field)
+ field = ""
+ else:
+ field += c
+ # добавить символ в поле
+ if field:
+ fields.append(field) # добавить последнее поле в список
+ return fields
+
+def escape_html(text):
+ text = text.replace("&", "&")
+ text = text.replace("<", "<")
+ text = text.replace(">", ">")
+ return text
+
+if __name__ == '__main__':
+ main()
diff --git a/src-datatype/print_unicode.py b/src-datatype/print_unicode.py
new file mode 100644
index 0000000..f69c980
--- /dev/null
+++ b/src-datatype/print_unicode.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+import sys
+import unicodedata
+
+def print_unicode_table(word):
+ print("decimal hex chr {0:^40}".format("name"))
+ print("------- ----- --- {0:-<40}".format(""))
+
+ code = ord(" ")
+ end = sys.maxunicode
+
+ while code < end:
+ c = chr(code)
+ name = unicodedata.name(c, "*** unknown ***")
+ if word is None or word in name.lower():
+ print("{0:7} {0:5X} {0:^3c} {1}".format(code, name.title()))
+ code += 1
+# End print_unicode_table
+
+# Start main script
+word = None
+
+if len(sys.argv) > 1:
+ if sys.argv[1] in ("-h", "--help"):
+ print("usage: {0} [string]".format(sys.argv[0]))
+ word = 0
+ else:
+ word = sys.argv[1].lower()
+
+if word != 0:
+ print_unicode_table(word)
+
+#End main script
diff --git a/src-datatype/print_unicode.py~ b/src-datatype/print_unicode.py~
new file mode 100644
index 0000000..4fbbac7
--- /dev/null
+++ b/src-datatype/print_unicode.py~
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+import sys
+import unicodedata
+
+def print_unicode_table(word):
+ print("decimal hex chr {0:^40}".format("name"))
+ print("------- ----- --- {0:-<40}".format(""))
+
+ code = ord(" ")
+ end = sys.maxunicode
+
+ while code < end:
+ c = chr(code)
+ name = unicodedata.name(c, "*** unknown ***")
+ if word is None or word in name.lower():
+ print("{0:7} {0:5X} {0:^3c} {1}".format(code, name.title()))
+ code += 1
+
+
+word = None
+
+if len(sys.argv) > 1:
+ if sys.argv[1] in ("-h", "--help"):
+ print("usage: {0} [string]".format(sys.argv[0]))
+ word = 0
+ else:
+ word = sys.argv[1].lower()
+
+if word != 0:
+ print_unicode_table(word)
diff --git a/src-datatype/quadratic.py b/src-datatype/quadratic.py
index 505b345..77bcc69 100644
--- a/src-datatype/quadratic.py
+++ b/src-datatype/quadratic.py
@@ -18,6 +18,7 @@ def get_float(msg, allow_zero):
return x
# End get_float
+
# Start 1st block
print("ax\N{SUPERSCRIPT TWO} + bx + c = 0")
a = get_float("enter a: ", False)
@@ -34,7 +35,7 @@ if discriminant == 0:
else:
if discriminant > 0:
root = math.sqrt(discriminant)
- else: # discriminant < 0
+ else: # discriminant < 0
root = cmath.sqrt(discriminant)
x1 = (-b + root) / (2 * a)
x2 = (-b - root) / (2 * a)
diff --git a/src-datatype/quadratic.py~ b/src-datatype/quadratic.py~
new file mode 100644
index 0000000..505b345
--- /dev/null
+++ b/src-datatype/quadratic.py~
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+import cmath
+import math
+import sys
+
+# Start get_float
+def get_float(msg, allow_zero):
+ x = None
+ while x is None:
+ try:
+ x = float(input(msg))
+ if not allow_zero and abs(x) < sys.float_info.epsilon:
+ print("zero is not allowed")
+ x = None
+
+ except ValueError as err:
+ print(err)
+ return x
+# End get_float
+
+# Start 1st block
+print("ax\N{SUPERSCRIPT TWO} + bx + c = 0")
+a = get_float("enter a: ", False)
+b = get_float("enter b: ", False)
+c = get_float("enter c: ", False)
+# End 1st block
+
+# Start 2d block
+x1 = None
+x2 = None
+discriminant = (b ** 2) - (4 * a * c)
+if discriminant == 0:
+ x1 = -(b / (2 * a))
+else:
+ if discriminant > 0:
+ root = math.sqrt(discriminant)
+ else: # discriminant < 0
+ root = cmath.sqrt(discriminant)
+ x1 = (-b + root) / (2 * a)
+ x2 = (-b - root) / (2 * a)
+# End 2d block
+
+# Start 3d block
+equation = ("{0}x\N{SUPERSCRIPT TWO} + {1}x + {2} = 0"
+ " \N{RIGHTWARDS ARROW} x = {3}").format(a, b, c, x1)
+if x2 is not None:
+ equation += " or x = {0}".format(x2)
+print(equation)
+# End 3d block
diff --git a/src-datatype/sample.csv b/src-datatype/sample.csv
new file mode 100644
index 0000000..91c5949
--- /dev/null
+++ b/src-datatype/sample.csv
@@ -0,0 +1,5 @@
+"COUNTRY",2000,2001,2002,2003,2004
+"ANTIGUA AND BARBUDA",0,0,0,0,0
+"ARGENTINA",37,35,33,36,39
+"BAHAMAS, THE",1,1,1,1,1
+"BAHRAIN",5,6,6,6,6
\ No newline at end of file
diff --git a/src-datatype/sample.csv~ b/src-datatype/sample.csv~
new file mode 100644
index 0000000..91c5949
--- /dev/null
+++ b/src-datatype/sample.csv~
@@ -0,0 +1,5 @@
+"COUNTRY",2000,2001,2002,2003,2004
+"ANTIGUA AND BARBUDA",0,0,0,0,0
+"ARGENTINA",37,35,33,36,39
+"BAHAMAS, THE",1,1,1,1,1
+"BAHRAIN",5,6,6,6,6
\ No newline at end of file
diff --git a/src-datatype/sample.html b/src-datatype/sample.html
new file mode 100644
index 0000000..4f713a6
--- /dev/null
+++ b/src-datatype/sample.html
@@ -0,0 +1,42 @@
+
+
+| "Country" |
+2000 |
+2001 |
+2002 |
+2003 |
+2004 |
+
+
+| "Antigua and Barbuda" |
+0 |
+0 |
+0 |
+0 |
+0 |
+
+
+| "Argentina" |
+37 |
+35 |
+33 |
+36 |
+39 |
+
+
+| "Bahamas, The" |
+1 |
+1 |
+1 |
+1 |
+1 |
+
+
+| "Bahrain" |
+5 |
+6 |
+6 |
+6 |
+6 |
+
+
diff --git a/src-datatype/sample.html~ b/src-datatype/sample.html~
new file mode 100644
index 0000000..4f713a6
--- /dev/null
+++ b/src-datatype/sample.html~
@@ -0,0 +1,42 @@
+
+
+| "Country" |
+2000 |
+2001 |
+2002 |
+2003 |
+2004 |
+
+
+| "Antigua and Barbuda" |
+0 |
+0 |
+0 |
+0 |
+0 |
+
+
+| "Argentina" |
+37 |
+35 |
+33 |
+36 |
+39 |
+
+
+| "Bahamas, The" |
+1 |
+1 |
+1 |
+1 |
+1 |
+
+
+| "Bahrain" |
+5 |
+6 |
+6 |
+6 |
+6 |
+
+