1908 lines
122 KiB
Plaintext
1908 lines
122 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"<!-- dom:TITLE: Тыпы коллекций -->\n",
|
||
"# Тыпы коллекций\n",
|
||
"<!-- dom:AUTHOR: С.В. Лемешевский Email:sergey.lemeshevsky@gmail.com at Институт математики НАН Беларуси -->\n",
|
||
"<!-- Author: --> \n",
|
||
"**С.В. Лемешевский** (email: `sergey.lemeshevsky@gmail.com`), Институт математики НАН Беларуси\n",
|
||
"\n",
|
||
"Date: **Mar 2, 2020**\n",
|
||
"\n",
|
||
"<!-- Common Mako variable and functions -->\n",
|
||
"<!-- -*- coding: utf-8 -*- -->\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"Рассматриваются кортежи и списки, а также новые типы коллекций, включая словари и множества.\n",
|
||
"\n",
|
||
"# Последовательности\n",
|
||
"<div id=\"collections:seq\"></div>\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",
|
||
"<div id=\"collections:seq:tuples\"></div>\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",
|
||
"<!-- dom:FIGURE: [fig-collections/seq_1.png, width=800 frac=1.0] Позиции элементов в кортеже <div id=\"collections:seq:fig:1\"></div> -->\n",
|
||
"<!-- begin figure -->\n",
|
||
"<div id=\"collections:seq:fig:1\"></div>\n",
|
||
"<!-- end figure -->\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",
|
||
"<div id=\"collections:seq:namedtuple\"></div>\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",
|
||
"<div id=\"collections:seq:lists\"></div>\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",
|
||
"<!-- dom:FIGURE: [fig-collections/seq_2.png, width=800 frac=1.0] Позиции элементов в списке <div id=\"collections:seq:fig:2\"></div> -->\n",
|
||
"<!-- begin figure -->\n",
|
||
"<div id=\"collections:seq:fig:2\"></div>\n",
|
||
"<!-- end figure -->\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 : Методы списков <div id=\"collections:seq:tbl:1\"></div>\n",
|
||
"\n",
|
||
"\n",
|
||
"<table border=\"1\">\n",
|
||
"<thead>\n",
|
||
"<tr><th align=\"left\"> Синтаксис </th> <th align=\"left\"> Описание </th> </tr>\n",
|
||
"</thead>\n",
|
||
"<tbody>\n",
|
||
"<tr><td align=\"left\"> <code>L.append(x)</code> </td> <td align=\"left\"> Добавляет элемент <code>x</code> в конец списка <code>L</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>L.count(x)</code> </td> <td align=\"left\"> Возвращает число вхождений элемента <code>x</code> в список <code>L</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>L.extend(m)</code> или <code>L += m</code> </td> <td align=\"left\"> Добавляет в конец списка L все элементы итерируемого объекта <code>m</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>L.index(x, start, end)</code> </td> <td align=\"left\"> Возвращает индекс самого первого (слева) вхождения элемента <code>x</code> в список <code>L</code> (или в срез <code>start:end</code> списка <code>L</code>); в противном случае возбуждает исключение <code>ValueError</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>L.insert(i, x)</code> </td> <td align=\"left\"> Вставляет элемент <code>x</code> в список <code>L</code> в позицию <code>int i</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>L.pop()</code> </td> <td align=\"left\"> Удаляет самый последний элемент из списка <code>L</code> и возвращает его в качестве результата </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>L.pop(i)</code> </td> <td align=\"left\"> Удаляет из списка <code>L</code> элемент с индексом <code>int i</code> и возвращает его в качестве результата </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>L.remove(x)</code> </td> <td align=\"left\"> Удаляет самый первый (слева) найденный элемент <code>x</code> из списка <code>L</code> или возбуждает исключение <code>ValueError</code>, если элемент <code>x</code>не будет найден <code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> </code>L.reverse()<code> </td> <td align=\"left\"> Переставляет в памяти элементы списка в обратном порядке </td> </tr>\n",
|
||
"<tr><td align=\"left\"> </code>L.sort()<code> </td> <td align=\"left\"> Сортирует список в памяти. Этот метод принимает те же необязательные аргументы </code>key<code> и </code>reverse<code> что и встроенная функция </code>sorted()` </td> </tr>\n",
|
||
"</tbody>\n",
|
||
"</table>\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",
|
||
"<div id=\"collections:seq:lists:gen\"></div>\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",
|
||
"<!-- Local Variables: -->\n",
|
||
"<!-- doconce-chapter-nickname: \"collections\" -->\n",
|
||
"<!-- doconce-section-nickname: \"seq\" -->\n",
|
||
"<!-- End: -->\n",
|
||
"# Множества\n",
|
||
"<div id=\"collections:sets\"></div>\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",
|
||
"<div id=\"collections:sets:set\"></div>\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": [
|
||
"<!-- dom:FIGURE: [fig-collections/set_1.png, width=400 frac=1.0] Множество – это неупорядоченная коллекция уникальных элементов <div id=\"collections:sets:fig:1\"></div> -->\n",
|
||
"<!-- begin figure -->\n",
|
||
"<div id=\"collections:sets:fig:1\"></div>\n",
|
||
"<!-- end figure -->\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",
|
||
"<!-- dom:FIGURE: [fig-collections/set_2.png, width=800 frac=1.0] Стандартные операторы множеств <div id=\"collections:sets:fig:2\"></div> -->\n",
|
||
"<!-- begin figure -->\n",
|
||
"<div id=\"collections:sets:fig:2\"></div>\n",
|
||
"<!-- end figure -->\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 : Методы и операторы множеств <div id=\"collections:sets:tbl:1\"></div>\n",
|
||
"\n",
|
||
"\n",
|
||
"<table border=\"1\">\n",
|
||
"<thead>\n",
|
||
"<tr><th align=\"left\"> Синтаксис </th> <th align=\"left\"> Описание </th> </tr>\n",
|
||
"</thead>\n",
|
||
"<tbody>\n",
|
||
"<tr><td align=\"left\"> <code>s.add(x)</code> </td> <td align=\"left\"> Добавляет элементы <code>x</code> во множество <code>s</code>, если они отсутствуют в <code>s</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.clear()</code> </td> <td align=\"left\"> Удаляет все элементы из множества <code>s</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.difference(t)</code>или <code>s-t</code> </td> <td align=\"left\"> Возвращает новое множество включающее элементы множества <code>s</code>, которые отсутствуют в множестве <code>t</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.difference_update(t)</code> или <code>s-=t</code> </td> <td align=\"left\"> Удаляет из множества <code>s</code> все элементы, присутствующие в множестве <code>t</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.discard(x)</code> </td> <td align=\"left\"> Удаляет элемент <code>x</code> из множества <code>s</code>, если он присутствует в множестве <code>s</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.intersection(t)</code> или <code>s & t</code> </td> <td align=\"left\"> Возвращает новое множество, включающее элементы, присутствующие одновременно в множествах <code>s</code> и <code>t</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.intersection_update(t)</code> или <code>s &= t</code> </td> <td align=\"left\"> Оставляет во множестве <code>s</code> пересечение множеств <code>s</code> и <code>t</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.isdisjoint(t)</code> </td> <td align=\"left\"> Возвращает <code>True</code>, если множества <code>s</code> и <code>t</code> не имеют общих элементов </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.issubset(t)</code> или <code>s <= t</code> </td> <td align=\"left\"> Возвращает <code>True</code>, если множество <code>s</code> эквивалентно множеству <code>t</code> или является его подмножеством; чтобы проверить, является ли множество <code>s</code> только подмножеством множества <code>t</code>, следует использовать проверку <code>s < t</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.issuperset(t)</code> или <code>s >= t</code> </td> <td align=\"left\"> Возвращает <code>True</code>, если множество <code>s</code> эквивалентно множеству <code>t</code> или является его надмножеством; чтобы проверить, является ли множество <code>s</code> только надмножеством множества <code>t</code>, следует использовать проверку <code>s > t</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.pop()</code> </td> <td align=\"left\"> Возвращает и удаляет случайный элемент множества <code>s</code> или возбуждает исключение <code>KeyError</code>, если <code>s</code> – это пустое множество </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.remove(x)</code> </td> <td align=\"left\"> Удаляет элемент <code>x</code> из множества <code>s</code> или возбуждает исключение <code>KeyError</code>, если элемент <code>x</code> отсутствует в множестве <code>s</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.symmetric_difference(t)</code> или <code>s ^ t</code> </td> <td align=\"left\"> Возвращает новое множество, включающее все элементы, присутствующие в множествах <code>s</code> и <code>t</code>, за исключением элементов, присутствующих в обоих множествах одновременно </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.symmetric_difference_update(t)</code> или <code>s ^= t</code> </td> <td align=\"left\"> Возвращает в множестве <code>s</code> результат строгой дизъюнкции множеств <code>s</code> и <code>t</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.union(t)</code> или <code>s | t</code> </td> <td align=\"left\"> Возвращает новое множество, включающее все элементы множества <code>s</code> и все элементы множества <code>t</code>, отсутствующие в множестве <code>s</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s.update(t)</code> или <code>s |= t</code> </td> <td align=\"left\"> Добавляет во множество <code>s</code> все элементы множества <code>t</code>, отсутствующие в множестве <code>s</code> </td> </tr>\n",
|
||
"</tbody>\n",
|
||
"</table>\n",
|
||
"\n",
|
||
"\n",
|
||
"### Генераторы множеств\n",
|
||
"\n",
|
||
"<div id=\"collections:sets:gen\"></div>\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",
|
||
"<div id=\"collections:sets:frozenset\"></div>\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",
|
||
"<!-- Local Variables: -->\n",
|
||
"<!-- doconce-chapter-nickname: \"collections\" -->\n",
|
||
"<!-- doconce-section-nickname: \"sets\" -->\n",
|
||
"<!-- End: -->\n",
|
||
"# Отображения\n",
|
||
"<div id=\"collections:maps\"></div>\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",
|
||
"<div id=\"collections:maps:dict\"></div>\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": [
|
||
"<!-- dom:FIGURE: [fig-collections/map_1.png, width=800 frac=1.0] Словарь – это неупорядоченная коллекция элементов (ключ, значение) с уникальными ключами <div id=\"collections:maps:fig:1\"></div> -->\n",
|
||
"<!-- begin figure -->\n",
|
||
"<div id=\"collections:maps:fig:1\"></div>\n",
|
||
"<!-- end figure -->\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 : Методы словарей <div id=\"collections:maps:tbl:1\"></div>\n",
|
||
"\n",
|
||
"\n",
|
||
"<table border=\"1\">\n",
|
||
"<thead>\n",
|
||
"<tr><th align=\"left\"> Синтаксис </th> <th align=\"left\"> Описание </th> </tr>\n",
|
||
"</thead>\n",
|
||
"<tbody>\n",
|
||
"<tr><td align=\"left\"> <code>d.clear()</code> </td> <td align=\"left\"> Удаляет все элементы из словаря <code>d</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.copy()</code> </td> <td align=\"left\"> Возвращает поверхностную копию словаря <code>d</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.fromkeys(s, v)</code> </td> <td align=\"left\"> Возвращает словарь типа <code>dict</code>, ключами которого являются элементы последовательности <code>s</code> значениями либо <code>None</code> либо <code>v</code>, если аргумент <code>v</code> определен </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.get(k)</code> </td> <td align=\"left\"> Возвращает значение ключа <code>k</code> или <code>None</code>, если ключ <code>k</code> отсутствует в словаре </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.get(k, v)</code> </td> <td align=\"left\"> Возвращает значение ключа <code>k</code> или <code>v</code>, если ключ <code>k</code> отсутствует в словаре </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.items()</code> </td> <td align=\"left\"> Возвращает представление всех пар (ключ, значение) в словаре <code>d</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.keys()</code> </td> <td align=\"left\"> Возвращает представление всех ключей словаря <code>d</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.pop(k)</code> </td> <td align=\"left\"> Возвращает значение ключа <code>k</code> и удаляет из словаря элемент с ключом <code>k</code> или возбуждает исключение <code>KeyError</code>, если ключ <code>k</code> отсутствует в словаре </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.pop(k, v)</code> </td> <td align=\"left\"> Возвращает значение ключа <code>k</code> и удаляет из словаря элемент с ключом <code>k</code> или возвращает значение <code>v</code>, если ключ <code>k</code> отсутствует в словаре </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.popitem()</code> </td> <td align=\"left\"> Возвращает и удаляет произвольную пару (ключ, значение) из словаря <code>d</code> или возбуждает исключение <code>KeyError</code>, если словарь <code>d</code> пуст </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.setdefault(k, v)</code> </td> <td align=\"left\"> То же что и <code>dict.get()</code> за исключением того, что, если ключ <code>k</code> в словаре отсутствует, в словарь вставляется новый элемент с ключом <code>k</code> и со значением <code>None</code> или <code>v</code>, если аргумент <code>v</code> задан </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.update(a)</code> </td> <td align=\"left\"> Добавляет в словарь <code>d</code> пары (ключ, значение) из <code>a</code>, которые отсутствуют в словаре <code>d</code> а для каждого ключа который уже присутствует в словаре <code>d</code> выполняется замена соответствующим значением из <code>a</code>; a может быть словарем итерируемым объектом с парами (ключ значение) или именованными аргументами </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>d.values()</code> </td> <td align=\"left\"> Возвращает представление всех значений в словаре <code>d</code> </td> </tr>\n",
|
||
"</tbody>\n",
|
||
"</table>\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",
|
||
"<div id=\"collections:maps:dict:gen\"></div>\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",
|
||
"<div id=\"collections:maps:defaultdict\"></div>\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",
|
||
"<!-- Local Variables: -->\n",
|
||
"<!-- doconce-chapter-nickname: \"collections\" -->\n",
|
||
"<!-- doconce-section-nickname: \"maps\" -->\n",
|
||
"<!-- End: -->\n",
|
||
"# Обход в цикле и копирование коллекций\n",
|
||
"<div id=\"collections:iterandcopy\"></div>\n",
|
||
"\n",
|
||
"После того как будет создана коллекция элементов данных, вполне\n",
|
||
"естественно возникает желание обойти все элементы, содержащиеся в\n",
|
||
"ней. Еще одна часто выполняемая операция – копирование коллекций. Из-за\n",
|
||
"того, что в языке Python повсеместно используются ссылки на объекты\n",
|
||
"(ради повышения эффективности), существуют некоторые особенности,\n",
|
||
"связанные с копированием.\n",
|
||
"\n",
|
||
"В этом разделе сначала мы рассмотрим итераторы языка Python, а затем\n",
|
||
"принципы копирования коллекций.\n",
|
||
"\n",
|
||
"## Итераторы, функции и операторы для работы с итерируемыми объектами\n",
|
||
"<div id=\"collections:iterandcopy:iterator\"></div>\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 : Общие функции и операторы для работы с итерируемыми объектами <div id=\"collections:iterandcopy:iterator:tbl:1\"></div>\n",
|
||
"\n",
|
||
"<table border=\"1\">\n",
|
||
"<thead>\n",
|
||
"<tr><th align=\"left\"> Синтаксис </th> <th align=\"left\"> Описание </th> </tr>\n",
|
||
"</thead>\n",
|
||
"<tbody>\n",
|
||
"<tr><td align=\"left\"> <code>s + t</code> </td> <td align=\"left\"> Возвращает конкатенацию последовательностей <code>s</code> и <code>t</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>s * n</code> </td> <td align=\"left\"> Возвращает конкатенацию из <code>int n</code> последовательностей <code>s</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>x in i</code> </td> <td align=\"left\"> Возвращает <code>True</code>, если элемент <code>x</code> присутствует в итерируемом объекте <code>i</code>, обратная проверка выполняется с помощью оператора <code>not in</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>all(i)</code> </td> <td align=\"left\"> Возвращает <code>True</code>, если все элементы итерируемого объекта <code>i</code> в логическом контексте оцениваются как значение <code>True</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>any(i)</code> </td> <td align=\"left\"> Возвращает <code>True</code>, если хотя бы один элемент итерируемого объекта <code>i</code> в логическом контексте оценивается как значение <code>True</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>enumerate (i,start)</code> </td> <td align=\"left\"> Обычно используется в циклах <code>for ... in</code>, чтобы получить последовательность кортежей <code>(index, item)</code>, где значения индексов начинают отсчитывать от <code>0</code> или от значения <code>start</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>len(x)</code> </td> <td align=\"left\"> Возвращает «длину» объекта <code>x</code>. Если <code>x</code> – коллекция, то возвращаемое число представляет количество элементов. Если <code>x</code> – строка, то возвращаемое число представляет количество символов </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>max(i, key)</code> </td> <td align=\"left\"> Возвращает наибольший элемент в итерируемом объекте <code>i</code> или элемент с наибольшим значением <code>key(item)</code>, если функция <code>key</code> определена </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>min(i, key)</code> </td> <td align=\"left\"> Возвращает наименьший элемент в итерируемом объекте <code>i</code> или элемент с наименьшим значением <code>key(item)</code>, если функция <code>key</code> определена </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>range(start, stop, step)</code> </td> <td align=\"left\"> Возвращает целочисленный итератор. С одним аргументом (<code>stop</code>) итератор представляет последовательность целых чисел от <code>0</code> до <code>stop-1</code>, с двумя аргументами (<code>start</code>, <code>stop</code>) – последовательность целых чисел от <code>start</code> до <code>stop-1</code>, с тремя аргументами – последовательность целых чисел от <code>start</code> до <code>stop-1</code> c шагом <code>step</code> </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>reversed(i)</code> </td> <td align=\"left\"> Возвращает итератор, который будет возвращать элементы итератора <code>i</code> в обратном порядке </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>sorted(i, key, reverse)</code> </td> <td align=\"left\"> Возвращает список элементов итератора <code>i</code> в отсортированном порядке. Аргумент <code>key</code> используется для выполнения сортировки DSU (Decorate, Sort, Undecorate – декорирование, сортировка, обратное декорирование). Если аргумент <code>reverse</code> имеет значение <code>True</code>, сортировка выполняется в обратном порядке </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>sum(i, start)</code> </td> <td align=\"left\"> Возвращает сумму элементов итерируемого объекта <code>i</code>, плюс ар гумент <code>start</code> (значение которого по умолчанию равно <code>0</code>). Объект <code>i</code> не должен содержать строк </td> </tr>\n",
|
||
"<tr><td align=\"left\"> <code>zip(i1, ..., iN)</code> </td> <td align=\"left\"> Возвращает итератор кортежей, используя итераторы от <code>i1</code> до <code>iN</code> </td> </tr>\n",
|
||
"</tbody>\n",
|
||
"</table>\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",
|
||
"<div id=\"collections:iterandcopy:copy\"></div>\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",
|
||
"<!-- Local Variables: -->\n",
|
||
"<!-- doconce-chapter-nickname: \"collections\" -->\n",
|
||
"<!-- doconce-section-nickname: \"iterandcopy\" -->\n",
|
||
"<!-- End: -->\n",
|
||
"\n",
|
||
"\n",
|
||
"<!-- Local Variables: -->\n",
|
||
"<!-- doconce-chapter-nickname: \"collections\" -->\n",
|
||
"<!-- End: -->"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
}
|