Добавлена глава по типам коллекций

This commit is contained in:
Sergey Lemeshevsky
2020-03-02 12:29:02 +03:00
parent af27efd7f6
commit 2756a9b834
20 changed files with 3162 additions and 950 deletions

View File

@@ -10,15 +10,13 @@
"<!-- Author: --> \n",
"**С.В. Лемешевский** (email: `sergey.lemeshevsky@gmail.com`), Институт математики НАН Беларуси\n",
"\n",
"Date: **Feb 24, 2020**\n",
"Date: **Feb 27, 2020**\n",
"\n",
"<!-- Common Mako variable and functions -->\n",
"<!-- -*- coding: utf-8 -*- -->\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"Здесь разберем как Python работает с переменными и определим, какие\n",
"типы данных можно использовать в рамках этого языка. Подробно рассмотрим модель\n",
"данных Python, а также механизмы создания и изменения значения\n",
@@ -1514,7 +1512,7 @@
"Как показано в примере, мы можем также использовать комбинированный\n",
"оператор присваивания с дублированием. \n",
"\n",
"# Форматирование строк с помощью метода `str.format()`\n",
"## Форматирование строк с помощью метода `str.format()`\n",
"<div id=\"datatype:strings:format\"></div>\n",
"\n",
"Метод `str.format()` представляет собой очень мощное и гибкое средство\n",
@@ -1608,6 +1606,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"В следующем разделе мы рассмотрим применение функции `str.format()`.\n",
"\n",
"<!-- Local Variables: -->\n",
"<!-- doconce-chapter-nickname: \"datatype\" -->\n",
"<!-- doconce-section-nickname: \"strings\" -->\n",
@@ -1615,8 +1615,195 @@
"# Примеры\n",
"<div id=\"datatype:examples\"></div>\n",
"\n",
"## Печать символов Юникода\n",
"<div id=\"datatype:examples:print-unicode\"></div>\n",
"\n",
"Рассмотрим небольшой, но достаточно поучительный пример использования\n",
"метода `str.format()`, в котором мы увидим применение спецификаторов\n",
"формата в реальном контексте. Программа, состоящая всего из 25 строк\n",
"выполняемого кода, находится в файле\n",
"[print_unicode.py](src-datatype/print_unicode.py). Она импортирует\n",
"два модуля, `sys` и `unicodedata` и определяет одну функцию \n",
"`print_unicode_table()`. Рассмотрение примера мы начнем\n",
"с запуска программы, чтобы увидеть, что она делает; затем мы\n",
"рассмотрим программный код в конце программы, где выполняется вся\n",
"фактическая работа; и в заключение рассмотрим функцию, определяемую в\n",
"программе."
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%run src-datatype/print_unnicode.py Spoked"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"При запуске без аргументов программа выводит таблицу всех символов\n",
"Юникода, начиная с пробела и до символа с наибольшим возможным\n",
"кодом. При запуске с аргументом, как показано в примере, выводятся \n",
"только те строки таблицы, где в названии символов Юникода содержится\n",
"значение строки-аргумента, переведенной в нижний регистр.\n",
"\n",
"Разберем исходный код программы:"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# Start main script\n",
"word = None\n",
"\n",
"if len(sys.argv) > 1:\n",
" if sys.argv[1] in (\"-h\", \"--help\"):\n",
" print(\"usage: {0} [string]\".format(sys.argv[0]))\n",
" word = 0\n",
" else:\n",
" word = sys.argv[1].lower()\n",
"\n",
"if word != 0:\n",
" print_unicode_table(word)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"После инструкций импортирования и определения функции\n",
"`print_unicode_table()` выполнение достигает программного кода,\n",
"показанного выше. Сначала предположим, что пользователь не указал в\n",
"командной строке искомое слово. Если аргумент командной строки\n",
"присутствует и это `-h` или `--help`, программа выводит информацию о\n",
"порядке использования и устанавливает флаг `word` в значение `0`, указывая\n",
"тем самым, что работа завершена. В противном случае в переменную `word`\n",
"записывается копия аргумента, введенного пользователем, с\n",
"преобразованием всех символов в нижний регистр. Если значение `word` не\n",
"равно `0`, программа выводит таблицу.\n",
"\n",
"При выводе информации о порядке использования применяется спецификатор\n",
"формата, который представляет собой простое имя формата, в данном\n",
"случае порядковый номер позиционного аргумента. Мы могли бы записать\n",
"эту строку, как показано ниже:"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"print(\"usage: {0[0]} [string]\".format(sys.argv))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"При таком подходе первый символ `0` соответствует порядковому номеру\n",
"позиционного аргумента, а `[0]` — это индекс элемента внутри\n",
"аргумента, и такой прием сработает, потому что `sys.argv` является\n",
"списком."
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def print_unicode_table(word):\n",
" print(\"decimal hex chr {0:^40}\".format(\"name\"))\n",
" print(\"------- ----- --- {0:-<40}\".format(\"\"))\n",
"\n",
" code = ord(\" \")\n",
" end = sys.maxunicode\n",
"\n",
" while code < end:\n",
" c = chr(code)\n",
" name = unicodedata.name(c, \"*** unknown ***\")\n",
" if word is None or word in name.lower():\n",
" print(\"{0:7} {0:5X} {0:^3c} {1}\".format(code, name.title()))\n",
" code += 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Первый вызов `str.format()` выводит текст `\"name\"`, отцентрированный в\n",
"поле вывода, шириной 40 символов, а второй вызов выводит пустую строку\n",
"в поле шириной 40 символов, используя символ `-` в качестве\n",
"символа-заполнителя, с выравниванием по левому краю. \n",
"\n",
"Как вариант, вторую строку функции можно было записать, как показано ниже:"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"print(\"------- ----- --- {0}\".format(\"-\" * 40))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Здесь мы использовали оператор дублирования строки (`*`), чтобы\n",
"создать необходимую строку, и просто вставили ее в строку формата.\n",
"\n",
"Текущий код символа Юникода сохраняется в переменной `code`, которая\n",
"инициализируется кодом пробела (`0x20`). В переменную end записывается\n",
"максимально возможный код символа Юникода, который может принимать\n",
"разные значения в зависимости от того, какая из кодировок\n",
"использовалась при компиляции Python.\n",
"\n",
"Внутри цикла `while` с помощью функции `chr()` мы получаем символ\n",
"Юникода, соответствующий числовому коду. Функция `unicodedata.name()`\n",
"возвращает название заданного символа Юникода, во втором\n",
"необязательном аргументе передается имя, которое будет использовано в\n",
"случае, когда имя символа не определено. \n",
"\n",
"Если пользователь не указывает аргумент командной строки (`word is None`)\n",
"или аргумент был указан и он входит в состав копии имени символа\n",
"Юникода, в которой все символы приведены к нижнему регистру, то\n",
"выводится соответствующая строка таблицы. \n",
"\n",
"Мы передаем переменную `code` методу `str.format()` один раз, но в\n",
"строке формата она используется трижды. Первый раз при выводе\n",
"значения `code` как целого числа в поле с шириной 7 символов (по\n",
"умолчанию в качестве символа-заполнителя используется пробел, поэтому\n",
"нет необходимости явно указывать его). Второй раз при выводе\n",
"значения `code` как целого числа в шестнадцатеричном формате символами\n",
"верхнего регистра в поле шириной 5 символов. И третий раз при выводе \n",
"символа Юникода, соответствующего значению code, с помощью\n",
"спецификатора формата `c`, отцентрированного в поле с минимальной \n",
"шириной 3 символа. Обратите внимание, что нам не потребовалось\n",
"указывать тип `d` в первом спецификаторе формата, потому что он\n",
"подразумевается по умолчанию для целых чисел. Второй аргумент \n",
"это имя символа Юникода, которое выводится с помощью метода\n",
"`str.title()`, в результате которого первый символ каждого слова\n",
"преобразуется к верхнему регистру, а остальные символы к нижнему. \n",
"\n",
"\n",
"## `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",
"<div id=\"datatype:examples:csv2html\"></div>\n",
"\n",
"Часто бывает необходимо представить данные в формате HTML. В этом\n",
"подразделе мы разработаем программу, которая читает данные из\n",
"файла в простом формате CSV (Comma Separated Value значения,\n",
"разделенные запятыми) и выводит таблицу HTML, содержащую эти\n",
"данные. В составе Python присутствует мощный и сложный модуль\n",
"для работы с форматом CSV и похожими на него модуль csv, но здесь\n",
"мы будем выполнять всю обработку вручную.\n",
"\n",
"В формате CSV каждая запись располагается на одной строке, а поля\n",
"внутри записи отделяются друг от друга запятыми. Каждое поле может\n",
"быть либо строкой, либо числом. Строки должны окружаться апострофами\n",
"или кавычками, а числа не должны окружаться кавычками, если они не\n",
"содержат запятые. Внутри строк допускается присутствие запятых, и они\n",
"не должны интерпретироваться как разделители полей. Мы будем исходить\n",
"из предположения, что первая запись в файле содержит имена полей. На\n",
"выходе будет воспроизводиться таблица в формате HTML с выравниванием\n",
"текста по левому краю (по умолчанию для HTML) и с выравниванием чисел\n",
"по правому краю, по одной строке на запись и по одной ячейке на поле.\n",
"\n",
"Ниже приводится маленький фрагмент файла с данными:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" \"COUNTRY\",2000,2001,2002,2003,2004\n",
" \"ANTIGUA AND BARBUDA\",0,0,0,0,0\n",
" \"ARGENTINA\",37,35,33,36,39\n",
" \"BAHAMAS, THE\",1,1,1,1,1\n",
" \"BAHRAIN\",5,6,6,6,6\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Предположим, что данные находятся в файле\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": [
" <table border='1'>\n",
" <tr bgcolor='lightgreen'>\n",
" <td>\"Country\"</td>\n",
" <td align='right'>2000</td>\n",
" <td align='right'>2001</td>\n",
" <td align='right'>2002</td>\n",
" <td align='right'>2003</td>\n",
" <td align='right'>2004</td>\n",
" </tr>\n",
" <tr bgcolor='white'>\n",
" <td>\"Antigua and Barbuda\"</td>\n",
" <td align='right'>0</td>\n",
" <td align='right'>0</td>\n",
" <td align='right'>0</td>\n",
" <td align='right'>0</td>\n",
" <td align='right'>0</td>\n",
" </tr>\n",
" <tr bgcolor='lightyellow'>\n",
" <td>\"Argentina\"</td>\n",
" <td align='right'>37</td>\n",
" <td align='right'>35</td>\n",
" <td align='right'>33</td>\n",
" <td align='right'>36</td>\n",
" <td align='right'>39</td>\n",
" </tr>\n",
" <tr bgcolor='white'>\n",
" <td>\"Bahamas, The\"</td>\n",
" <td align='right'>1</td>\n",
" <td align='right'>1</td>\n",
" <td align='right'>1</td>\n",
" <td align='right'>1</td>\n",
" <td align='right'>1</td>\n",
" </tr>\n",
" <tr bgcolor='lightyellow'>\n",
" <td>\"Bahrain\"</td>\n",
" <td align='right'>5</td>\n",
" <td align='right'>6</td>\n",
" <td align='right'>6</td>\n",
" <td align='right'>6</td>\n",
" <td align='right'>6</td>\n",
" </tr>\n",
" </table>\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"На рис. показано, как выглядит полученная таблица в веб-броузере.\n",
"\n",
"<!-- dom:FIGURE: [fig-datatype/example_1.png, width=400 frac=1.0] Таблица, произведенная программой csv2html.py, в броузере <div id=\"datatype:examples:fig:1\"></div> -->\n",
"<!-- begin figure -->\n",
"<div id=\"datatype:examples:fig:1\"></div>\n",
"![Таблица, произведенная программой csv2html.py, в броузере](fig-datatype/example_1.png)<!-- end figure -->\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(\"<table border='1'>\")\n",
"\n",
"def print_end():\n",
" print(\"</table>\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Мы могли бы не создавать эти две функции и просто вставить\n",
"соответствующие вызовы `print()` в функцию `main()`. Но мы предпочитаем\n",
"выделять логику, так как это делает реализацию более гибкой, хотя\n",
"в этом маленьком примере гибкость не имеет большого значения."
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def print_line(line, color, maxwidth):\n",
" print(\"<tr bgcolor='{0}'>\".format(color))\n",
" fields = extract_fields(line)\n",
" for field in fields:\n",
" if not field:\n",
" print(\"<td></td>\")\n",
" else:\n",
" number = field.replace(\",\", \"\")\n",
" try:\n",
" x = float(number)\n",
" print(\"<td align='right'>{0:d}</td>\".format(round(x)))\n",
" except ValueError:\n",
" field = field.title()\n",
" field = field.replace(\" And \", \" and \")\n",
" field = escape_html(field)\n",
" if len(field) <= maxwidth:\n",
" print(\"<td>{0}</td>\".format(field))\n",
" else:\n",
" print(\"<td>{0:.{1}} ...</td>\".format(field, maxwidth))\n",
" print(\"</tr>\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Мы не можем использовать метод `str.split(\",\")` для разбиения каждой\n",
"строки на поля, потому что запятые могут находиться внутри строк в\n",
"кавычках. Поэтому мы возложили эту обязанность на функцию\n",
"`extract_fields()`. Получив список строк полей (в виде строк без\n",
"окружающих их кавычек), мы выполняем обход списка и создаем для \n",
"каждого поля ячейку таблицы.\n",
"\n",
"Если поле пустое, мы выводим пустую ячейку. Если поле было заключено в\n",
"кавычки, это может быть строка или число в кавычках, содержащее\n",
"символы запятой, например `\"1,566\"`. Учитывая такую возможность, мы\n",
"создаем копию поля без запятых и пытаемся преобразовать ее в число\n",
"типа `float`. Если преобразование удалось, мы определяем выравнивание\n",
"в ячейке по правому краю, а значение поля округляется до ближайшего\n",
"целого, которое и выводится. Если преобразование не удалось,\n",
"следовательно, поле содержит строку. В этом случае мы с помощью метода\n",
"`str.title()` изменяем регистр символов и замещаем слово «And» на слово\n",
"«and», устраняя побочный эффект действия метода \n",
"`str.title()`. Затем выполняется экранирование специальных символов\n",
"HTML и выводится либо поле целиком, либо первые `maxwidth` символов\n",
"с добавлением многоточия. Простейшей альтернативой использованию\n",
"вложенного поля замены в строке формата является получение \n",
"среза строки, например:"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"print(\"<td>{0} ...</td>\".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(\"&\", \"&amp;\")\n",
" text = text.replace(\"<\", \"&lt;\")\n",
" text = text.replace(\">\", \"&gt;\")\n",
" return text"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Эта функция просто замещает каждый специальный символ HTML\n",
"соответствующей ему сущностью языка HTML. В первую очередь, конечно,\n",
"мы должны заменить символ амперсанда и угловые скобки, хотя порядок не\n",
"имеет никакого значения. \n",
"\n",
"<!-- Local Variables: -->\n",
"<!-- doconce-chapter-nickname: \"datatype\" -->\n",
"<!-- doconce-section-nickname: \"examples\" -->\n",
"<!-- End: -->\n",
"# Упражнения\n",
"<div id=\"datatype:exercises\"></div>\n",
"\n",
"\n",
"\n",
"<!-- --- begin exercise --- -->\n",
"\n",
"## Изменение вывода символов Юникода\n",
"<div id=\"datatype:exercises:1\"></div>\n",
"\n",
"Измените программу `print_unicode.py` так, чтобы пользователь мог\n",
"вводить в командной строке несколько разных слов и получать\n",
"только те строки из таблицы символов Юникода, в которых содержатся все\n",
"слова, указанные пользователем. Это означает, что мы сможем вводить\n",
"такие команды:"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"print_unicode_ans.py greek symbol"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<!-- --- begin hint in exercise --- -->\n",
"\n",
"**Подсказка.**\n",
"Один из способов достижения поставленной цели состоит в том,\n",
"чтобы заменить переменную `word` (которая может хранить `0`, `None` \n",
"или строку) списком `words`. Не забудьте изменить информацию о порядке\n",
"использования. В результате изменений не более десяти строк\n",
"программного кода добавится и не более десяти строк изменится.\n",
"\n",
"<!-- --- end hint in exercise --- -->\n",
"Имя файла: `print_unicode_ans.py`.\n",
"\n",
"<!-- --- end exercise --- -->\n",
"\n",
"\n",
"\n",
"\n",
"<!-- --- begin exercise --- -->\n",
"\n",
"## Изменение `quadratic.py`\n",
"<div id=\"datatype:exercises:2\"></div>\n",
"\n",
"Измените программу `quadratic.py` так, чтобы она не выводила\n",
"коэффициенты со значением `0.0`, а отрицательные коэффициенты\n",
"выводились бы как `-n`, а не `+ - n`.\n",
"Имя файла: `quadratic_ans.py`.\n",
"\n",
"<!-- --- end exercise --- -->\n",
"\n",
"\n",
"\n",
"\n",
"<!-- --- begin exercise --- -->\n",
"\n",
"## Использование функции `escape()`\n",
"<div id=\"datatype:exercises:escape\"></div>\n",
"\n",
"Удалите функцию `escape_html()` из программы `cvs2html.py` и\n",
"используйте вместо нее функцию `xml.sax.saxutils.escape()` из модуля \n",
"`xml.sax.saxutils`.\n",
"\n",
"<!-- --- begin hint in exercise --- -->\n",
"\n",
"**Подсказка.**\n",
"Для этого потребуется добавить одну новую строку\n",
"(с инструкцией `import`), удалить пять строк (с ненужной функцией)\n",
"и изменить одну строку (задействовать функцию\n",
"`xml.sax.saxutils.escape()` вместо `escape_html()`).\n",
"\n",
"<!-- --- end hint in exercise --- -->\n",
"Имя файла: `cvs2html_ans1.py`.\n",
"\n",
"<!-- --- end exercise --- -->\n",
"\n",
"\n",
"\n",
"\n",
"<!-- --- begin exercise --- -->\n",
"\n",
"## Добавление обработки параметров командной строки в `csv2html.py`\n",
"<div id=\"datatype:exercises:process_option\"></div>\n",
"\n",
"Измените программу `cvs2html.py` еще раз и добавьте в нее новую\n",
"функцию с именем `process_options()`. Эта функция должна вызываться из\n",
"функции main() и возвращать кортеж с двумя значениями: \n",
"`maxwidth` (типа `int`) и `format` (типа `str`). При вызове функция\n",
"`process_options()` должна устанавливать `maxwidth` в значение по\n",
"умолчанию `100`, а строку `format` в значение по умолчанию `\".0f\"`,\n",
"которое будет использоваться как спецификатор формата при выводе чисел.\n",
"Если пользователь вводит в командной строке `-h` или `--help`,\n",
"должно выводиться сообщение о порядке использования и возвращаться\n",
"кортеж `(None, None)`. (В этом случае функция `main()` ничего\n",
"делать не должна.) В противном случае функция должна прочитать\n",
"аргументы командной строки и выполнить соответствующие\n",
"присваивания. Например, устанавливать значение переменной `maxwidth`,\n",
"если задан аргумент `maxwidth=n`, и точно так же устанавливать \n",
"значение переменной `format`, если задан аргумент `format=s`. Ниже\n",
"приводится сеанс работы с программой, когда пользователь затребовал\n",
"инструкцию о порядке работы:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" Terminal> csv2html2_ans.py -h\n",
" usage:\n",
" csv2html.py [maxwidth=int] [format=str] < infile.csv > outfile.html\n",
" maxwidth - необязательное целое число. Если задано, определяет\n",
" максимальное число символов для строковых полей. В противном случае\n",
" используется значение по умолчанию 100.\n",
" \n",
" format - формат вывода чисел. Если не задан, по умолчанию используется\n",
" формат \".0f\".\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"А ниже приводится пример командной строки, в которой установ-\n",
"лены оба аргумента:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" Terminal> csv2html2_ans.py maxwidth=20 format=0.2f < mydata.csv > mydata.html\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<!-- --- begin hint in exercise --- -->\n",
"\n",
"**Подсказка.**\n",
"Не забудьте изменить функцию `print_line()` так, чтобы она\n",
"использовала переменную `format` при выводе чисел для этого вам\n",
"придется передавать функции дополнительный аргумент, добавить одну \n",
"строку и изменить еще одну строку. И это немного затронет функцию\n",
"`main()`. Функция `process_options()` должна содержать порядка\n",
"двадцати пяти строк (включая девять строк с текстом сообщения о\n",
"порядке использования).\n",
"\n",
"<!-- --- end hint in exercise --- -->\n",
"Имя файла: `cvs2html_ans2.py`.\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"<!-- Local Variables: -->\n",
"<!-- doconce-chapter-nickname: \"datatype\" -->\n",
"<!-- doconce-section-nickname: \"exercises\" -->\n",
"<!-- End: -->\n",
"\n",
"\n",
"\n",
"\n",
"<!-- Local Variables: -->\n",
"<!-- doconce-chapter-nickname: \"datatype\" -->\n",
"<!-- End: -->"
"<!-- End: -->\n",
"<!-- --- end exercise --- -->"
]
}
],