Объекты множества в языке Python представляют собой неупорядоченные контейнеры
(см. подраздел 1.1 лаб. раб. №3) уникальных хэшируемых
объектов.
Объект является хэшируемым, если он имеет значение хэш-функции,
которое не меняется в течение времени существования объекта, т.е. поддерживает метод
__hash__() и может быть сравним с другими объектами с помощью метода
__eq__()
(см. подраздел 1.3 лаб. раб. №3). Все хэшируемые объекты
являются неизменяемыми объектами и принадлежат ABC-классу Hashable (см.
раздел 1 лаб. раб. №3).
Хэшируемость объектов позволяет использовать их в качестве элементов
множества и ключей словарей (см. подраздел 2.1), поскольку эти структуры данных
используют значения хэш-функции.
В языке Python все встроенные неизменяемые объекты (такие, как числа,
логические значения, строки и кортежи) являются хэшируемыми:
>>>
from
collections
import
Hashable
>>>
isinstance
(1.25e-1, Hashable)
True
>>>
isinstance
(
False
, Hashable)
True
>>>
isinstance
(
'Web'
, Hashable)
True
>>>
isinstance
((1,2,3),collections.Hashable)
True
в то время как изменяемые контейнеры, такие как изменяемые множества
(см. подраздел 1.1), словари (см. подраздел 2.1) и списки
(см. раздел 2 лаб. раб. №3) – нет:
>>>
isinstance
([
'a'
,
'b'
,
'c'
], Hashable
False
Объекты, которые являются экземплярами созданных пользователем
классов, являются хэшироваными по умолчанию, при сравнении между собой они не равны и значения их
хэшей являются значениям их id().
Объекты множества могут быть использованы при проверке на наличие
элементов в последовательности, при удалении дубликатов из последовательности и при выполнении
математических операций над множествами, таких как объединение, пересечение и вычитание.
Имеется два встроенных типа (класса) множеств:
set и frozenset
(см. подраздел 2.1).
Тип set является изменяемым множеством или
просто множеством. Как изменяемый объект, он не может быть использован ни в качестве ключа в
словарях, ни в качестве элемента другого множества.
Тип frozenset является неизменяемым
множеством. Поэтому может быть ключом в словаре и элементом другого множества.
Создавать экземпляры изменяемого множества (тип set) можно с помощью
литерала, поместив в фигурные скобки элементы множества неизменяемых типов, разделенные запятыми:
>>>
a_set={1,2,
'a'
,
'b'
}
>>>
a_set
{'b', 1, 2, 'a'},
или с помощью генератора элементов множества (см. подраздел 3.2).
Проверим изменяемость (нехэшируемость) множеств:
>>>
isinstance
(a_set, Hashable)
False.
Также для создания множества можно использовать конструктор –
встроенную функцию set([iterable])
(см. подраздел 8.1 лаб. раб. №1), аргументом которой является
итерабельный объект. Поэтому в объекты множества можно преобразовать такие последовательности, как
строки, списки, кортежи и диапазоны. Если строка, список, кортеж или
диапазон содержат одинаковые элементы, после преобразования из них останется только один:
>>>
set
(
'ABBA'
)
{'B','A'}.
Отметим, что, поскольку множество является неупорядоченным
контейнером, то и элементы полученного множества могут указываться интерпретатором в произвольном
порядке.
Раз элементы множества не могут быть изменяемыми типами, то и
итерабельный тип, указанный в качестве аргумента функции set() не может
содержать изменяемые (нехэшируемые) элементы:
>>>
set
([1,2,[3,4]])
TypeError: unhashable type: 'list'
Для создания объектов множества неизменяемого типа
frozenset необходимо использовать конструктор – встроенную функцию frozenset()
(см. подраздел 8.1 лаб. раб. №1,
аргументом которой является итерабельный объект:
>>>
frozenset
((
'a'
,
'c'
,
'd'
,
'c'
))
frozenset({'d', 'a', 'c'})
.
Экземпляры типов set и
frozenset, являясь контейнерами:
>>>
import
collections
>>>
isinstance
({1,2},collections.Container)
True
>>>
isinstance
(frozenset({1,2}), collections.Container)
True
и не являясь последовательностями:
>>>
isinstance
({1,2},collections.Sequence)
False
>>>
isinstance
(frozenset({1,2}), collections.Sequence)
False
поддерживают лишь часть операций, свойственных последовательностям (те из них, которые также
поддерживают и контейнеры):
Можно добавить, что объекты изменяемого множества set принадлежат
ABC-классу MutableSet:
>>>
s={1,2,3}
>>>
isinstance
(s,collections.MutableSet)
True,
а объекты неизменяемого класса frozenset – нет:
>>>
fs=frozenset(s)
>>>
isinstance
(fs,collections.MutableSet)
False
Имеется два способа добавления элементов в существующее множество:
Отметим, что объекты типа frozenset, будучи неизменяемыми множествами, не имеют методов добавления элементов к множеству.
Имеется несколько способов удаления элементов из существующего множества:
В логическом контексте пустое множество set() соответствует False,
любое другое – True.
Отметим, что объекты типа frozenset, будучи
неизменяемыми множествами, не имеют методов удаления элементов из множества.
Python имеет несколько методов сравнения множеств:
Метод copy() используется для "поверхностного" копирования списков
(см. раздел 4)):
>>>
b_set=a_set.copy()
>>>
b_set
{1, 2, 5, 6}.
Python имеет несколько методов для выполнения основных операций над множествами:
Словари в языке Python имеют тип (класс) dict и представляют собой множество пар вида ключ:значение. Словари в языке Python похожи на ассоциативные массивы языка Jaxascript.
Для создания словаря в виде литерала необходимо поместить его элементы, заданные в виде пар
ключ:значение и разделеные запятыми, в фигурные скобки:
>>>
a_dict={
'alpha'
:1,
'beta'
:2,
'gamma'
:3}
>>>
a_dict
{'alpha': 1, 'beta': 2, 'gamma': 3}
В качестве ключа необходимо использовать только неизменяемые
(хэшируемые) типы: числа (целые и с плавающей точкой), строки, логические значения, кортежи,
диапазоны и неизменяемые множества. В качестве значения могут быть заданы любые из рассмотренных
типов, включая изменяемые множества и словари.
Словари также можно задавать с помощью конструктора – встроенной
функции dict()
(см. подраздел 8.1 лаб. раб. №1). Если при
вызове функция не имеет аргументов, то создается пустой список:
>>>
dict
()
{},
если имеет, то для создания словаря могут быть использованы следующие варианты задания аргументов:
Выше четырьмя разными способами были созданы словари a_dict(),
b_dict(), c_dict() и
d_dict(), имеющие одно и то же значение. Проверим это:
>>>
a_dict==b_dict==c_dict==d_dict
True.
Если ключи и значения словаря заданы последовательностями, то для
создания словаря также можно использовать встроенную функцию
zip(*iterable)
(см. подраздел 8.1 лаб. раб. №1), которая
возвращает итератор, элементами которого являются кортежи, где i-й кортеж содержит i-е элементы
каждого аргумента последовательностей или итерабельных объектов.
Если последовательности, явдяющиеся аргументами функции, имеют разную длину, то формируемые кортежи
имеют число элементов, равное длине минимальной последовательности. Если указан один элемент –
функция возвращает итератор, состоящий из одноэлементных кортежей. Если аргументы не указаны –
возвращается пустой итератор.
Пусть, например, ключи словаря представлены списком
key_list, а значения – кортежом
value_tuple:
>>>
key_list=[
'a'
,
'b'
,
'c'
]
>>>
value_tuple=(1.32,
'value'
, [1,2,3], 25)
Теперь с помощью функции zip(), аргументами
которой являются последовательности key_list и
value_tuple, создаем итератор с именем zipped:
>>>
zipped=
zip
(key_list, value_tuple),
который имеет тип zip:
>>>
type
(zipped)
<class 'zip'>
Остается только преобразовать его с помощью конструктора в словарь:
>>>
e_dict=
dict
(zipped)
>>>
e_dict
{'a': 1.32, 'b': 'value', 'c': [1, 2, 3]}
Следует сказать, что словари в настоящее время являются единственными
представителями ABC-класса Mapping, объекты которого ставят в
соответсвие неизменяемые значения произвольным объектам. Являются изменяемыми контейнерами типа
Mapping:
>>>
import
collections
>>>
isinstance
({1:
'a'
,2:
'b'
,3:
'c'
},collections.Container)
True
>>>
isinstance
({1:
'a'
,2:
'b'
,3:
'c'
},collections.Mapping)
True
>>>
isinstance
({1:
'a'
,2:
'b'
,3:
'c'
},collections.MutableMapping)
True
Для получения значения словаря по ключу нобходимо воспользоваться
выражением:
>>>
a_dict[
'beta'
]
2,
если указанный ключ отсутствует – возбуждается исключение KeyError:
>>>
a_dict[
'delta'
]
KeyError: 'delta'.
Чтобы получить все значения словаря следует использовать оператор
for in:
>>>
for
key
in
a_dict:
print
(key,
'='
,a_dict[key])
alpha = 1
beta = 2
gamma = 3
Можно изменять значение ключа:
>>>
a_dict[
'alpha'
]=11
>>>
a_dict
{'alpha': 11, 'beta': 2, 'gamma': 3}
и добавлять новые пары в словарь:
>>>
a_dict[
'epsilon'
]=5
>>>
a_dict
{'alpha': 22, 'beta': 2, 'gamma': 3, 'epsilon': 5}
Для удаления ключа необходимо указать:
>>>
del
a_dict[
'alpha'
]
>>>
]
{'beta': 2, 'gamma': 3, 'epsilon': 5}.
Словари так же, как последовательности и множества поддерживают
функцию определения числа элементов len() и оператор
in, позволяющий определить принадлежность элемента контейнеру.
Пустой словарь – {} в логическом контексте равен False, все
остальные словари – True.
Словари поддерживают следующие методы:
В литералах при создании списков, множеств и словарей помимо указания перечня их элементов (см. подразделы 2.1 лаб. раб. №3, 1.1 и 2.1) можно также указать генераторы элементов этих контейнеров.
Например, создание списка кубов целых чилел от 1 до 10 можно осуществить следующим образом:
>>>
a_list=[x**3
for
x
in
range
(1, 11)]
>>>
a_list
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000].
Выражение x**3 for x in range(1,11)
является генераторным выражением. Оно имеет тип генератора:
>>>
type
(x**3
for
x
in
range
(1, 11))
<class 'generator'>
и состоит из выражения x**3, за которым следует оператор
for для итерабельного типа. В таком виде генераторное выражение может
использоваться только в качестве единичного аргумента в функциях. В остальных случаях необходимо
указывать его в скобках, например при анализе, является ли тип generator
итерабельным:
>>>
import
collections
>>>
isinstance
((x**3
for
x
in
range
(1, 11)), collections.Iterable)
True.
В приведенном примере сформированные кубы целых чисел сохранены в
памяти в виде списка. Для длинных последовательностей это не всегда удобно. Рассмотрим вариант
генерации кубов чисел без сохранения их в памяти:
>>>
gen=(x**3
for
x
in
range
(1, 11))
>>>
for
x
in
gen:
print
x, end=
' '
)
1, 8, 27, 64, 125, 216, 343, 512, 729, 1000.
Поскольку значения генератора gen не
сохранены в памяти повторное его использование ничего не дает:
>>>
for
x
in
gen:
print
x, end=
' '
)
Создадим с помощью генератора множество букв, из которых состоит предложение
"Карл украл у Клары кораллы", представив их в верхнем регистре:
>>>
a_set={x
for
x
in
'Карл украл у Клары кораллы'
.upper()}
>>>
a_set
{'О', 'Л', 'К', 'А', ' ', 'Ы', 'Р', 'У'}
.
В качестве последнего примера использования генераторов рассмотрим создание словаря, ключами
которого являются числа, заданные в списке, а значениями – квадратные корни этих чисел:
>>>
{x:x**(1/2)
for
x
in
[2, 5, 25] }
{25: 5.0, 2: 1.4142135623730951, 5: 2.23606797749979}.
Формировать элементы последовательностей также можно с использованием
встроенной функции map()
(см. подраздел 1.5.2 лаб. раб. №6).
В подразделе 1.4 при описании метода copy() был
использован термин поверхностная копия. Поскольку существует еще и глубокая копия, дадим
разъяснение этим терминам.
Операторы присваивания в языке Python не копируют объекты, они только
сооздают ссылки на объект. Для контейнеров, которые являются изменяемыми или содержат изменяемые
элементы, возникает иногда необходимость их копирования – чтобы можно было изменить копию, не
изменяя исходные значения.
Модуль copy содержит два метода:
Различие между между поверхностным (англ. shallow) и глубоким (англ. deep) копированием имеет смысл только для составных объектов (объектов, которые содержат другие объекты, например, списки, словари или экземпляры классов):
В качестве примера создадим и сравним поверзностную и глубокую копию словаря:
>>>
import
copy
>>>
a_dict={1:5,2:{3:25}}
>>>
a_dict
{1: 5, 2: {3: 25}}
>>>
b_dict=copy.copy(a_dict)
>>>
b_dict
{1: 5, 2: {3: 25}}
>>>
b_dict[2][3]=77
>>>
a_dict
{1: 5, 2: {3: 77}}.
Видно, что при использовании поверхностного копирования словаря
(функции copy()) изменения в полученной копии привели к изменению оригинала. При использовании
глубокого копирования (функции deepcopy()) этого не произойдет:
>>>
a_dict={1:5,2:{3:25}}
>>>
c_dict=copy.deepcopy(a_dict)
>>>
c_dict[2][3]=77
>>>
a_dict
{1: 5, 2: {3: 25}}.
Для создания "поверхностной" копии помимо метода
copy() модуля copy() можно также использовать:
Разработать программу на языке Python, которая выполняет следующее:
Номер п/п | Множество | Словарь | |||
---|---|---|---|---|---|
Создание | Методы | Операции | Создание | Методы | |
1 | 3 | 1,3 | 4 | 1 | 2,5,8 |
2 | 2 | 1,4 | 3 | 2 | 2,6,9 |
3 | 1 | 1,5 | 2 | 3 | 3,5,1 |
4 | 3 | 2,3 | 1 | 4 | 3,6,8 |
5 | 2 | 2,4 | 4 | 5 | 4,5,9 |
6 | 1 | 2,5 | 3 | 1 | 4,6,1 |
7 | 3 | 1,3 | 2 | 2 | 7,9,5 |
8 | 2 | 1,4 | 1 | 3 | 2,5,8 |
9 | 1 | 1,5 | 4 | 4 | 2,6,9 |
10 | 3 | 2,3 | 3 | 5 | 3,5,1 |
11 | 2 | 2,4 | 2 | 1 | 3,6,8 |
12 | 1 | 2,5 | 1 | 2 | 4,5,9 |
13 | 3 | 1,3 | 4 | 3 | 4,6,1 |
14 | 2 | 1,4 | 3 | 4 | 7,9,5 |
15 | 1 | 1,5 | 2 | 5 | 2,5,8 |
16 | 3 | 2,3 | 1 | 1 | 2,6,9 |
17 | 2 | 2,4 | 4 | 2 | 3,5,1 |
18 | 1 | 2,5 | 3 | 3 | 3,6,8 |
19 | 3 | 1,3 | 2 | 4 | 4,5,9 |
20 | 2 | 1,4 | 1 | 5 | 4,6,1 |