Skip to content
Snippets Groups Projects
Commit 5de00f22 authored by S.Guliaev's avatar S.Guliaev
Browse files

added lecture 3

parent 586db5ed
No related branches found
No related tags found
No related merge requests found
# Python
## Типы данных-коллекции
### Раздел 1. Типы данных-последовательности
Тип данных, реализующий последовательность, это такой тип данных, для которого доступен оператор вхождения, функция получения длины (len()), получения среза и к нему можно доступаться как к итератору. Мы уже рассмотрели тип str, в будущем будут рассмотрены bytearray и bites, а на данный момент сосредоточимся на tuple и лист. Все эти типы являются встроенными.
#### Кортежи
Кортежем (tuple) называется упорядоченная последовательность из 0 или более ссылок на объекты. Кортежи поддерживают тот же оператор извлечения среза, что и строки. Кортежи являются неизменяемыми, так что если в ходе работы вам необходима изменяемая последовательность — обратитесь к списком, либо преобразуйте кортеж в список при помощи вызова list().
Как и всегда, tuple может быть вызван как функция. Без передачи аргумента, будет возвращен пустой объект. При передачи в качестве аргумента объекта типа tuple, будет создана его поверхностная копия. Во всех остальных случаях будет совершена попытка привести аргумент к типу tuple. Данная функция принимает не более одного аргумента.
Кортежи могут быть созданы заключением элементов в скобки (даже если элементов нет () — пустой кортеж) или перечислением элементов кортежа через запятую (только не при передачи таким образом кортежа в качестве аргумента функции.
Для кортежей доступны всего два метода: count и index. t.count(x) возвращает число вхождений x в t, а t.index(x) возвращает индекс самого левого вхождения x в t, либо возбуждает ValueError, если x не входит в t. К тому же, для кортежей доступны операторы + (конкатенация), \* (повторение), [] (взятие среза), in и not in (проверка на вхождение). Комбинированные версии присваивания += и \*= могут использоваться, несмотря на то, что кортежи неизменяемы. Просто будет создан новый объект, который будет присвоен переменной (то же происходит и со строками). Для кортежей доступны операции сравнения: < <= == != >= >. Они выполняют сравнение поэлементно и рекурсивно.
Кортежи позволяют выполнить один из самых известных трюков в Python:
```python
x = 1
y = 2
x, y = y, x
print(x, y)
```
2 1
Также, если элементами итератора являются кортежи, то вы их сразу можете распаковывать:
```python
for hero, villain in (('Batman', 'Joker'), ('Superman', 'Lex Luthor'), ('Green Lantern', 'Sinestro')):
print(hero, 'vs', villain)
```
Batman vs Joker
Superman vs Lex Luthor
Green Lantern vs Sinestro
#### Списки
Список есть упорядоченная последовательность из нуля или более ссылок на объекты. Как и кортежи, для списков доступно взятие среза. Но в отличие от кортежей, списки изменяемы. Как следствие, мы можем изменять не только список целиком или его отдельные элементы, но и целые срезы в нем.
Тип list может быть вызван как функция. Без аргументов list() вернет пустой список. Если в качестве аргумента был передан объект типа list, то будет создана его поверхностная копия. Если аргумент дан, но не является объектом класса list, то будет произведена попытка приведения его к типу list. Данная функция принимает не более одного аргумента.
Списки могут быть созданы также перечислением элементов через запятую в квадратных скобках или при помощи генераторов списков.
Для типа list доступны операции сравнения, работают аналогично случаю с кортежами.
Списки могут быть вложены в друг друга, проитерированы, от них можно взять срез, — все то же, что и для кортежей. Можно использовать операторы in, not int, +, +=, *, *=, функцию len() и конструкцию del.
Также есть оператор \*, который может использоваться для получения остальной части списка в случае выбора нескольких элементов:
```python
heroes = ['Batman', 'Superman', 'Green Lantern', 'Flash']
batman, *rest = heroes
print(batman, rest)
batman, *mid, flash = heroes
print(batman, mid, flash)
```
Batman ['Superman', 'Green Lantern', 'Flash']
Batman ['Superman', 'Green Lantern'] Flash
Также есть оператор распаковки \*, который используется для передачи элементов списка по отдельности в качестве аргументов функции:
```python
heroes = ['Batman', 'Superman', 'Green Lantern', 'Flash']
def print4(a, b, c, d):
print(a)
print(b)
print(c)
print(d)
print4(*heroes)
```
Batman
Superman
Green Lantern
Flash
Для списков доступны следующие методы:
| Метод | Описание |
| ----- | :------- |
| L.append(x) | Добавляет элемент x в конец списка L |
| L.count(x) | Подсчитывает число вхождений элемента x в список L |
| L.extend(m) | Добавляет элементы m, к которому должен быть обеспечен доступ как к итератору, в конец списка L (то же, что и L += m |
| L.index(x, start, end) | Возвращает индекс самого левого вхождения x в L. Если start и end заданы, то поиск происходит в срезе L[start:end]. Если элемент не найден, то возбуждается исключение ValueError |
| L.insert(i, x) | Вставляет элемент x на позицию с индексом i в список L |
| L.pop() | Удаляет последний элемент списка L и возвращает его |
| L.pop(i) | Удаляет элемент списка L с индексом i и возвращает его |
| L.remove(x) | Удаляет самое левое вхождение элемента x из списка L. Если элемент не найден, то возбуждается исключение ValueError |
| L.reverse() | Разворачивает список |
| L.sort(...) | Сортирует список. Аргумент key отвечает за функцию порядка, а reversed за способ сортировки (по невозрастанию / неубыванию) |
#### Генераторы списков
Для получения списка как результат какой-то операции над итератором используются генераторы списков. Есть две формымы генератора списков:
[выражение for элемент in итератор]
[выражение for элемент in итератор if условие]
В самом простом случае выражение и есть элемент:
```python
print([x for x in range(10)])
print([2*x for x in range(10)])
print([2*x for x in range(10) if x % 3 == 0])
```
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[0, 6, 12, 18]
Последняя форма в разы удобнее, чем запись:
```python
lst = []
for x in range(10):
if x % 3 == 0:
lst.append(2*x)
print(lst)
```
[0, 6, 12, 18]
### Раздел 2. Типы-множества
Типы данных-множества — типы, для которых доступны оператор вхождения in, функция len и доступ, как к итератору. В Python есть два типа множеств — set и frozenset. Тип frozenset является неизменяемым, поэтому для него недоступны методы для типа set, которые изменяют объект. В остальном они идентичны.
Только хешируемые объекты могут быть добавлены в множество. Все встроенные неизменяемые типы являются хешируемыми.
#### Множества
Множество типа set есть неупорядоченная коллекция из нуля или более ссылок на хешируемые объекты. Множества изменяемы, так что в них можно добавлять и удалять элементы. Будучи неупорядоченными, понятие индекса или позиции для них не имеет смысла.
Для создания множества используется либо вызов set(), который без аргументов создает пустое множество. С аргументом типа set создается поверхностная копия множества, а с другим аргументом выполняется попытка приведения к множеству. Данная функция не принимает более одного аргумента. Множество может быть также создано путем заключения элементов в фигурные скобки, но стоит учитывать, что пустое множество не может быть создано таким образом, так как {} создаст пустой словарь.
Множество всегда хранит уникальные элементы:
```python
set('hello world') == {'h', 'e', 'l', 'o', ' ', 'w', 'r', 'd'}
```
True
Множества поддерживают функцию len(), которое возвращает число элементов множества.
Для типа set доступны следующие методы:
| Метод | Описание |
| ----- | :------- |
| s.add(x) | Добавляет элемент x во множество s, если такого там нет |
| s.clear() | Удаляет все элементы множества s |
| s.copy() | Создает неглубокую копию множества s |
| s.difference(t) | Возвращает новое множество, которое содержит все элементы множества s, которые не входят во множество t. Эквивалент s - t |
| s.differenct_update(t) | Удаляет все элементы t из множества s. Эквивалент s -= t |
| s.discard(x) | Удаляет элемент x из множества s |
| s.intersection(t) | Возвращает новое множество, которое содержит элементы множества s, которые в то же время являются элементами множества t. Эквивалент s & t |
| s.intersection_update(t) | Удаляет из множества s все элементы, которые не входят в t. Эквивалент s &= t |
| s.isdisjoint(t) | Возвращает True, если у множеств s и t нет общих элементов |
| s.issubset(t) | Возвращает True, если s есть подмножество (несобственное) t. Эквивалент s <= t |
| s.issuperset(t) | Возвращает True, если t есть подмножество (несобственное) s. Эквивалент t <= s |
| s.pop() | Удаляет случайный элемент s и возвращает его. Возбуждает исключение KeyError, если множесво пустое |
| s.remove(x) | Удаляет элемент x из множества s. Возбуждает исключение KeyError, если x не входит в s |
| s.symmetric_difference(t) | Возвращает новое множество, которое содержит элементы, которые либо содержатся в s и не содержатся в t, либо содержатся в t и не содержатся в s. Эквивалент s ^ t |
| s.symmetric_difference_update(t) | Записывает в s симметрическую разность s и t. Эквивалент s ^= t |
| s.union(t) | Возвращает новое множество, которое содержит все элементы множеств s и t |
| s.update(t) | Добавляет все элементы множества t во множество s |
Последние два метода эквивалентны s | t и s |= t соответственно.
#### Генераторы множеств
В целом то же, что и для списков, но сам генератор обозначается фигурными скобками:
```python
print({x for x in range(10)})
print({2*x for x in range(10)})
print({2*x for x in range(10) if x % 3 == 0})
```
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18}
{0, 18, 12, 6}
### Раздел 3. Типы-отображения
Типы отображения — наборы пар "ключ - значение". Единственным встроенным типом-отображением является dictionary, который отображает хешируемые объекты на ссылки на другие объекты.
#### Словари
Тип dict (словарь) это упорядоченная коллекция пар "ключ - значение". Раньше dict был неупорядоченным типом, поэтому во избежания ошибок при исполнении кода более старыми интерпретаторами, советую вам придерживаться отношения к словорям как к неупорядоченным последовательностям.
Словари поддерживают оператор вхождения in, функцию len(), и доступ как к итератору. Среди операций сравнения поддерживаются только == и !=.
Как и обычно, тип dict может быть вызван как функция. Если ей не переданы аргументы, то создается пустой словарь. Если передан аргумент с типом-отображением, то создается словарь на основе этого аргумента. Например, если аргумент типа dict, то будет создана его поверхностная копия. Можно также передать аргумент-последовательность, каждый элемент в котором — последовательность из двух элементов: ключа и значения. Также пустой словарь можно создать при помощи конструкции {}, а словарь с элементами — перечислив пары ключ - значение в фигурных скобках через запятую, отделяя ключи от значений двоеточием:
{ключ1 : значение1, ключ2 : значение2}
К тому же доступны генераторы словарей.
Мы можем доступаться к элементам словаря, используя ключ: d[ключ] вернет значение элемента с ключем *ключ*.
Для добавления новых элементов используется оператор присваивания: d[новый\_ключ] = новое\_значение.
Для типа dict доступны следующие методы:
| Метод | Описание |
| ----- | :------- |
| d.clear() | Удаляет все элементы словаря d |
| d.copy() | Возвращает поверхностную копию словаря d |
| d.fromkeys(s, v) | Возвращает словарь, где ключами являются элементы последователности s, а значения равны v или None, если v не указано |
| d.get(k) | Возвращает значение, которое соответствует ключу k или None, если такого нет |
| d.get(k, v) | Возвращает значение, которое соответствует ключу k или v, если такого нет |
| d.items() | Возвращает view (read-only итератор), содержащий пары (ключ, значение) словаря d |
| d.keys() | Возвращает view, содержащий ключи словаря d |
| d.pop(k) | Удаляет элемент, соответствующий ключу k и возвращает его. Если такого нет, то возбуждается исключение KeyError |
| d.pop(k, v) | Удаляет элемент, соответствующий ключу k и возвращает его. Если такого нет, то возвращается значение v |
| d.popitem() | Удаляет из словаря d и возвращает некоторую пару (ключ, значение). Возбуждает исключение KeyError, если d пуст |
| d.setdefault(k, v) | ТТо же, что и d.get(k), но если такого элемента нет, то создается новый со значением None или v, если указано |
| d.values() | Возвращает view всех значений словаря d |
#### Генераторы словарей
Генераторы словарей имеют две уже знакомые нам формы:
[выражение\_ключа : выражение\_значения for ключ, значение in итератор]
[выражение\_ключа : выражение\_значения for ключ, значение in итератор if условие]
### Раздел 4. Итераторы. Функции и операци для работы с итераторами
Тип данных называется итерируемым, если он может возвращать свои элементы по одному. Технически, любой объект, реализующий метод \_\_iter\_\_() является итерируемым и может предоставить итератор. Итератор — объект, реализуюзий метод \_\_next()\_\_, возвращающий следующее значение и возбуждающий исключение StopIteration, если элементов больше нет.
Для итерируемых объектов доступны следующие функции и операторы:
| Функция или оператор | Описание |
| -------------------- | :------- |
| s + t | Возвращает конкатенацию последовательностей s и t |
| s * n | Возвращает последовательность, которая является результатом повторения последовательности s n раз |
| x in t | Проверяет, есть ли в последовательности i элемент x |
| all(i) | Возвращает True, если все элементы i при приведении к типу bool имеют значение True |
| any(i) | Возвращает True, если один из элементов i при приведении к типу bool имеет значение True |
| enumerate(i, start) | Возвращает последовательность элементов (индекс, значение) для итератора i, начиная с индекса 0 или start, если данный аргумент задан |
| len(x) | Возвращает число элементов в x |
| max(i, key) | Возвращает максимальный элемент в i. Если аргумент key задан, то возвращает элемент, для которого key максимален |
| min(i, key) | Возвращает минимальный элемент в i. Если аргумент key задан, то возвращает элемент, для которого key минимален |
| range(start, stop, step) | Возвращает итератор, содержащий целые числа от start до stop с шагом step. Аргумент start включен в последовательность, а stop — нет |
| reversed(i) | Возвращает итератор, в котором элементы идут в обратном порядке |
| sorted(i, key, reverse) | Возвращает отсортированный по неубыванию итератор. Если задан аргумент key, то сортировка идет по значением key(x) для каждого элемента x. Если reversre указан как True, то сортировка идет по невозрастанию |
| sum(i, start) | Возвращает сумму элементов в итераторе i плюс start. Если start не задан, то принимается равным 0 |
| zip(i1, ..., iN) | Возвращает итератор из кортежей, состоящий из элементов i1, ..., iN. Количество кортежей определяется минимальной длиной i1, ..., iN |
### Раздел 5. Копирование коллекций
При присваивании объектов будет выполнено присваивание по ссылке:
```python
x = ['Nightwing', 'Robin', 'Catwoman']
y = x
x[0] = 'Alfred'
print(y)
```
['Alfred', 'Robin', 'Catwoman']
Для создания поверхностной копии можно использовать оператор среза:
```python
x = ['Nightwing', 'Robin', 'Catwoman']
y = x[:]
x[0] = 'Alfred'
print(y)
```
['Nightwing', 'Robin', 'Catwoman']
Но поверхностная копия имеет ограничения, связанные с тем, что при ее создании создаются копии лишь самих элементов. Если они в свою очередь являются ссылками, то мы снова столкнемся с проблемой:
```python
dc_villains = [['Lex Luther', 'General Zod'], ['Joker', 'Scarecrow']]
villains = dc_villains[:]
dc_villains[1][1] = 'Pinguin'
print(villains)
```
[['Lex Luther', 'General Zod'], ['Joker', 'Pinguin']]
Чтобы избежать этого, необходимо использовать функцию deepcopy() модуля copy, которая создает глубокую копию объекта:
```python
from copy import deepcopy
dc_villains = [['Lex Luther', 'General Zod'], ['Joker', 'Scarecrow']]
villains = deepcopy(dc_villains)
dc_villains[1][1] = 'Pinguin'
print(villains)
```
[['Lex Luther', 'General Zod'], ['Joker', 'Scarecrow']]
### Раздел 6. Практика: vedis и matplotlib
Есть достаточно интересный модуль vedis, который предоставляет доступ к key-value store типа Redis на диске, но при этом API этого доступа совпадает с доступом к словарю.
Решим с использованием модуля vedis [задачу о гипотезе Колатца](https://lambda-it.ru/post/26) и сделаем визуализацию при помощи matplotlib.
Для начала напишем функцию, которая из текущего числа получает следующее в последовательности:
```python
def next_kolatz(x):
if x & 1:
return 3*x + 1
return x >> 1
```
Если число x является нечетным (последний разряд в двоичной системе равен единице), то мы возвращаем 3x + 1. В противном случае, мы делим число на 2 (соответствует сдвигу вправо на один разряд в двоичной системе счисления). Теперь импортируем модуль vedis. При помощи него мы будем хранить длину цепочки для чисел, которые мы уже встречали. Также напишем функцию, которая вычисляет и возвращает длину цепочки для заданного числа x, записывает ее в хранилище, а также записывает в хранилище длины цепочек для всех промежуточных чисел:
```python
def get_kolatz_length(x, storage):
cur = x
try:
return int(storage.get(cur))
except KeyError as e:
pass
stack = [cur]
while True:
cur = next_kolatz(cur)
try:
length = int(storage.get(cur))
break
except KeyError as e:
pass
stack.append(cur)
for item in stack[::-1]:
length += 1
storage.set(item, length)
return int(storage.get(x))
```
Теперь напишем функцию, которая возвращает число, меньшее заданного, для которого данная цепочка максимальна и длину цепочки:
```python
def get_max_kolatz_length(n, storage):
num = max(range(1, n+1), key=lambda x: get_kolatz_length(x, storage))
return num, get_kolatz_length(num, storage)
```
Теперь остается только инициализировать хранилище и испытать наши функции:
```python
from vedis import Vedis
db = Vedis('storage.db')
db.set(1, 1)
print(get_max_kolatz_length(100000, db))
db.close()
```
(77031, 351)
True
Теперь построим обычный scatter plot при помощи matplotlib:
```python
import matplotlib.pyplot as plt
db = Vedis('storage.db')
X = range(1, 101)
Y = [get_kolatz_length(x, db) for x in X]
db.close()
plt.scatter(X, Y)
plt.title('Визуализация длин цепочек Колатца')
plt.xlabel('Число')
plt.ylabel('Длина цепочки')
plt.show()
```
![png](lecture_3_files/lecture_3_35_0.png)
### Раздел 7. Домашнее задание
Решить задачи после третьей главы Саммерфилда
Загуглить гипотезу Гольдбаха
Загуглить динамическое программирование
Написать функцию, которая принимает в качестве аргумента множество и функцию и при помощи matplotlib изображает график заданной функции на множестве значений. Добавьте несколько дополнительных аргументов: например, возможность сделать одну из осей логарифмической, выбрать разные цветовые схемы, разные типы графиков и т.д.
Решить задачу, которая будет опубликована в субботу
%% Cell type:markdown id: tags:
# Python
## Типы данных-коллекции
### Раздел 1. Типы данных-последовательности
Тип данных, реализующий последовательность, это такой тип данных, для которого доступен оператор вхождения, функция получения длины (len()), получения среза и к нему можно доступаться как к итератору. Мы уже рассмотрели тип str, в будущем будут рассмотрены bytearray и bites, а на данный момент сосредоточимся на tuple и лист. Все эти типы являются встроенными.
#### Кортежи
Кортежем (tuple) называется упорядоченная последовательность из 0 или более ссылок на объекты. Кортежи поддерживают тот же оператор извлечения среза, что и строки. Кортежи являются неизменяемыми, так что если в ходе работы вам необходима изменяемая последовательность — обратитесь к списком, либо преобразуйте кортеж в список при помощи вызова list().
Как и всегда, tuple может быть вызван как функция. Без передачи аргумента, будет возвращен пустой объект. При передачи в качестве аргумента объекта типа tuple, будет создана его поверхностная копия. Во всех остальных случаях будет совершена попытка привести аргумент к типу tuple. Данная функция принимает не более одного аргумента.
Кортежи могут быть созданы заключением элементов в скобки (даже если элементов нет () — пустой кортеж) или перечислением элементов кортежа через запятую (только не при передачи таким образом кортежа в качестве аргумента функции.
Для кортежей доступны всего два метода: count и index. t.count(x) возвращает число вхождений x в t, а t.index(x) возвращает индекс самого левого вхождения x в t, либо возбуждает ValueError, если x не входит в t. К тому же, для кортежей доступны операторы + (конкатенация), \* (повторение), [] (взятие среза), in и not in (проверка на вхождение). Комбинированные версии присваивания += и \*= могут использоваться, несмотря на то, что кортежи неизменяемы. Просто будет создан новый объект, который будет присвоен переменной (то же происходит и со строками). Для кортежей доступны операции сравнения: < <= == != >= >. Они выполняют сравнение поэлементно и рекурсивно.
Кортежи позволяют выполнить один из самых известных трюков в Python:
%% Cell type:code id: tags:
``` python
x = 1
y = 2
x, y = y, x
print(x, y)
```
%% Output
2 1
%% Cell type:markdown id: tags:
Также, если элементами итератора являются кортежи, то вы их сразу можете распаковывать:
%% Cell type:code id: tags:
``` python
for hero, villain in (('Batman', 'Joker'), ('Superman', 'Lex Luthor'), ('Green Lantern', 'Sinestro')):
print(hero, 'vs', villain)
```
%% Output
Batman vs Joker
Superman vs Lex Luthor
Green Lantern vs Sinestro
%% Cell type:markdown id: tags:
#### Списки
Список есть упорядоченная последовательность из нуля или более ссылок на объекты. Как и кортежи, для списков доступно взятие среза. Но в отличие от кортежей, списки изменяемы. Как следствие, мы можем изменять не только список целиком или его отдельные элементы, но и целые срезы в нем.
Тип list может быть вызван как функция. Без аргументов list() вернет пустой список. Если в качестве аргумента был передан объект типа list, то будет создана его поверхностная копия. Если аргумент дан, но не является объектом класса list, то будет произведена попытка приведения его к типу list. Данная функция принимает не более одного аргумента.
Списки могут быть созданы также перечислением элементов через запятую в квадратных скобках или при помощи генераторов списков.
Для типа list доступны операции сравнения, работают аналогично случаю с кортежами.
Списки могут быть вложены в друг друга, проитерированы, от них можно взять срез, — все то же, что и для кортежей. Можно использовать операторы in, not int, +, +=, *, *=, функцию len() и конструкцию del.
Также есть оператор \*, который может использоваться для получения остальной части списка в случае выбора нескольких элементов:
%% Cell type:code id: tags:
``` python
heroes = ['Batman', 'Superman', 'Green Lantern', 'Flash']
batman, *rest = heroes
print(batman, rest)
batman, *mid, flash = heroes
print(batman, mid, flash)
```
%% Output
Batman ['Superman', 'Green Lantern', 'Flash']
Batman ['Superman', 'Green Lantern'] Flash
%% Cell type:markdown id: tags:
Также есть оператор распаковки \*, который используется для передачи элементов списка по отдельности в качестве аргументов функции:
%% Cell type:code id: tags:
``` python
heroes = ['Batman', 'Superman', 'Green Lantern', 'Flash']
def print4(a, b, c, d):
print(a)
print(b)
print(c)
print(d)
print4(*heroes)
```
%% Output
Batman
Superman
Green Lantern
Flash
%% Cell type:markdown id: tags:
Для списков доступны следующие методы:
| Метод | Описание |
| ----- | :------- |
| L.append(x) | Добавляет элемент x в конец списка L |
| L.count(x) | Подсчитывает число вхождений элемента x в список L |
| L.extend(m) | Добавляет элементы m, к которому должен быть обеспечен доступ как к итератору, в конец списка L (то же, что и L += m |
| L.index(x, start, end) | Возвращает индекс самого левого вхождения x в L. Если start и end заданы, то поиск происходит в срезе L[start:end]. Если элемент не найден, то возбуждается исключение ValueError |
| L.insert(i, x) | Вставляет элемент x на позицию с индексом i в список L |
| L.pop() | Удаляет последний элемент списка L и возвращает его |
| L.pop(i) | Удаляет элемент списка L с индексом i и возвращает его |
| L.remove(x) | Удаляет самое левое вхождение элемента x из списка L. Если элемент не найден, то возбуждается исключение ValueError |
| L.reverse() | Разворачивает список |
| L.sort(...) | Сортирует список. Аргумент key отвечает за функцию порядка, а reversed за способ сортировки (по невозрастанию / неубыванию) |
#### Генераторы списков
Для получения списка как результат какой-то операции над итератором используются генераторы списков. Есть две формымы генератора списков:
[выражение for элемент in итератор]
[выражение for элемент in итератор if условие]
В самом простом случае выражение и есть элемент:
%% Cell type:code id: tags:
``` python
print([x for x in range(10)])
print([2*x for x in range(10)])
print([2*x for x in range(10) if x % 3 == 0])
```
%% Output
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[0, 6, 12, 18]
%% Cell type:markdown id: tags:
Последняя форма в разы удобнее, чем запись:
%% Cell type:code id: tags:
``` python
lst = []
for x in range(10):
if x % 3 == 0:
lst.append(2*x)
print(lst)
```
%% Output
[0, 6, 12, 18]
%% Cell type:markdown id: tags:
### Раздел 2. Типы-множества
Типы данных-множества — типы, для которых доступны оператор вхождения in, функция len и доступ, как к итератору. В Python есть два типа множеств — set и frozenset. Тип frozenset является неизменяемым, поэтому для него недоступны методы для типа set, которые изменяют объект. В остальном они идентичны.
Только хешируемые объекты могут быть добавлены в множество. Все встроенные неизменяемые типы являются хешируемыми.
#### Множества
Множество типа set есть неупорядоченная коллекция из нуля или более ссылок на хешируемые объекты. Множества изменяемы, так что в них можно добавлять и удалять элементы. Будучи неупорядоченными, понятие индекса или позиции для них не имеет смысла.
Для создания множества используется либо вызов set(), который без аргументов создает пустое множество. С аргументом типа set создается поверхностная копия множества, а с другим аргументом выполняется попытка приведения к множеству. Данная функция не принимает более одного аргумента. Множество может быть также создано путем заключения элементов в фигурные скобки, но стоит учитывать, что пустое множество не может быть создано таким образом, так как {} создаст пустой словарь.
Множество всегда хранит уникальные элементы:
%% Cell type:code id: tags:
``` python
set('hello world') == {'h', 'e', 'l', 'o', ' ', 'w', 'r', 'd'}
```
%% Output
True
%% Cell type:markdown id: tags:
Множества поддерживают функцию len(), которое возвращает число элементов множества.
Для типа set доступны следующие методы:
| Метод | Описание |
| ----- | :------- |
| s.add(x) | Добавляет элемент x во множество s, если такого там нет |
| s.clear() | Удаляет все элементы множества s |
| s.copy() | Создает неглубокую копию множества s |
| s.difference(t) | Возвращает новое множество, которое содержит все элементы множества s, которые не входят во множество t. Эквивалент s - t |
| s.differenct_update(t) | Удаляет все элементы t из множества s. Эквивалент s -= t |
| s.discard(x) | Удаляет элемент x из множества s |
| s.intersection(t) | Возвращает новое множество, которое содержит элементы множества s, которые в то же время являются элементами множества t. Эквивалент s & t |
| s.intersection_update(t) | Удаляет из множества s все элементы, которые не входят в t. Эквивалент s &= t |
| s.isdisjoint(t) | Возвращает True, если у множеств s и t нет общих элементов |
| s.issubset(t) | Возвращает True, если s есть подмножество (несобственное) t. Эквивалент s <= t |
| s.issuperset(t) | Возвращает True, если t есть подмножество (несобственное) s. Эквивалент t <= s |
| s.pop() | Удаляет случайный элемент s и возвращает его. Возбуждает исключение KeyError, если множесво пустое |
| s.remove(x) | Удаляет элемент x из множества s. Возбуждает исключение KeyError, если x не входит в s |
| s.symmetric_difference(t) | Возвращает новое множество, которое содержит элементы, которые либо содержатся в s и не содержатся в t, либо содержатся в t и не содержатся в s. Эквивалент s ^ t |
| s.symmetric_difference_update(t) | Записывает в s симметрическую разность s и t. Эквивалент s ^= t |
| s.union(t) | Возвращает новое множество, которое содержит все элементы множеств s и t |
| s.update(t) | Добавляет все элементы множества t во множество s |
Последние два метода эквивалентны s | t и s |= t соответственно.
#### Генераторы множеств
В целом то же, что и для списков, но сам генератор обозначается фигурными скобками:
%% Cell type:code id: tags:
``` python
print({x for x in range(10)})
print({2*x for x in range(10)})
print({2*x for x in range(10) if x % 3 == 0})
```
%% Output
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18}
{0, 18, 12, 6}
%% Cell type:markdown id: tags:
### Раздел 3. Типы-отображения
Типы отображения — наборы пар "ключ - значение". Единственным встроенным типом-отображением является dictionary, который отображает хешируемые объекты на ссылки на другие объекты.
#### Словари
Тип dict (словарь) это упорядоченная коллекция пар "ключ - значение". Раньше dict был неупорядоченным типом, поэтому во избежания ошибок при исполнении кода более старыми интерпретаторами, советую вам придерживаться отношения к словорям как к неупорядоченным последовательностям.
Словари поддерживают оператор вхождения in, функцию len(), и доступ как к итератору. Среди операций сравнения поддерживаются только == и !=.
Как и обычно, тип dict может быть вызван как функция. Если ей не переданы аргументы, то создается пустой словарь. Если передан аргумент с типом-отображением, то создается словарь на основе этого аргумента. Например, если аргумент типа dict, то будет создана его поверхностная копия. Можно также передать аргумент-последовательность, каждый элемент в котором — последовательность из двух элементов: ключа и значения. Также пустой словарь можно создать при помощи конструкции {}, а словарь с элементами — перечислив пары ключ - значение в фигурных скобках через запятую, отделяя ключи от значений двоеточием:
{ключ1 : значение1, ключ2 : значение2}
К тому же доступны генераторы словарей.
Мы можем доступаться к элементам словаря, используя ключ: d[ключ] вернет значение элемента с ключем *ключ*.
Для добавления новых элементов используется оператор присваивания: d[новый\_ключ] = новое\_значение.
Для типа dict доступны следующие методы:
| Метод | Описание |
| ----- | :------- |
| d.clear() | Удаляет все элементы словаря d |
| d.copy() | Возвращает поверхностную копию словаря d |
| d.fromkeys(s, v) | Возвращает словарь, где ключами являются элементы последователности s, а значения равны v или None, если v не указано |
| d.get(k) | Возвращает значение, которое соответствует ключу k или None, если такого нет |
| d.get(k, v) | Возвращает значение, которое соответствует ключу k или v, если такого нет |
| d.items() | Возвращает view (read-only итератор), содержащий пары (ключ, значение) словаря d |
| d.keys() | Возвращает view, содержащий ключи словаря d |
| d.pop(k) | Удаляет элемент, соответствующий ключу k и возвращает его. Если такого нет, то возбуждается исключение KeyError |
| d.pop(k, v) | Удаляет элемент, соответствующий ключу k и возвращает его. Если такого нет, то возвращается значение v |
| d.popitem() | Удаляет из словаря d и возвращает некоторую пару (ключ, значение). Возбуждает исключение KeyError, если d пуст |
| d.setdefault(k, v) | ТТо же, что и d.get(k), но если такого элемента нет, то создается новый со значением None или v, если указано |
| d.values() | Возвращает view всех значений словаря d |
#### Генераторы словарей
Генераторы словарей имеют две уже знакомые нам формы:
[выражение\_ключа : выражение\_значения for ключ, значение in итератор]
[выражение\_ключа : выражение\_значения for ключ, значение in итератор if условие]
%% Cell type:markdown id: tags:
### Раздел 4. Итераторы. Функции и операци для работы с итераторами
Тип данных называется итерируемым, если он может возвращать свои элементы по одному. Технически, любой объект, реализующий метод \_\_iter\_\_() является итерируемым и может предоставить итератор. Итератор — объект, реализуюзий метод \_\_next()\_\_, возвращающий следующее значение и возбуждающий исключение StopIteration, если элементов больше нет.
Для итерируемых объектов доступны следующие функции и операторы:
| Функция или оператор | Описание |
| -------------------- | :------- |
| s + t | Возвращает конкатенацию последовательностей s и t |
| s * n | Возвращает последовательность, которая является результатом повторения последовательности s n раз |
| x in t | Проверяет, есть ли в последовательности i элемент x |
| all(i) | Возвращает True, если все элементы i при приведении к типу bool имеют значение True |
| any(i) | Возвращает True, если один из элементов i при приведении к типу bool имеет значение True |
| enumerate(i, start) | Возвращает последовательность элементов (индекс, значение) для итератора i, начиная с индекса 0 или start, если данный аргумент задан |
| len(x) | Возвращает число элементов в x |
| max(i, key) | Возвращает максимальный элемент в i. Если аргумент key задан, то возвращает элемент, для которого key максимален |
| min(i, key) | Возвращает минимальный элемент в i. Если аргумент key задан, то возвращает элемент, для которого key минимален |
| range(start, stop, step) | Возвращает итератор, содержащий целые числа от start до stop с шагом step. Аргумент start включен в последовательность, а stop — нет |
| reversed(i) | Возвращает итератор, в котором элементы идут в обратном порядке |
| sorted(i, key, reverse) | Возвращает отсортированный по неубыванию итератор. Если задан аргумент key, то сортировка идет по значением key(x) для каждого элемента x. Если reversre указан как True, то сортировка идет по невозрастанию |
| sum(i, start) | Возвращает сумму элементов в итераторе i плюс start. Если start не задан, то принимается равным 0 |
| zip(i1, ..., iN) | Возвращает итератор из кортежей, состоящий из элементов i1, ..., iN. Количество кортежей определяется минимальной длиной i1, ..., iN |
%% Cell type:markdown id: tags:
### Раздел 5. Копирование коллекций
При присваивании объектов будет выполнено присваивание по ссылке:
%% Cell type:code id: tags:
``` python
x = ['Nightwing', 'Robin', 'Catwoman']
y = x
x[0] = 'Alfred'
print(y)
```
%% Output
['Alfred', 'Robin', 'Catwoman']
%% Cell type:markdown id: tags:
Для создания поверхностной копии можно использовать оператор среза:
%% Cell type:code id: tags:
``` python
x = ['Nightwing', 'Robin', 'Catwoman']
y = x[:]
x[0] = 'Alfred'
print(y)
```
%% Output
['Nightwing', 'Robin', 'Catwoman']
%% Cell type:markdown id: tags:
Но поверхностная копия имеет ограничения, связанные с тем, что при ее создании создаются копии лишь самих элементов. Если они в свою очередь являются ссылками, то мы снова столкнемся с проблемой:
%% Cell type:code id: tags:
``` python
dc_villains = [['Lex Luther', 'General Zod'], ['Joker', 'Scarecrow']]
villains = dc_villains[:]
dc_villains[1][1] = 'Pinguin'
print(villains)
```
%% Output
[['Lex Luther', 'General Zod'], ['Joker', 'Pinguin']]
%% Cell type:markdown id: tags:
Чтобы избежать этого, необходимо использовать функцию deepcopy() модуля copy, которая создает глубокую копию объекта:
%% Cell type:code id: tags:
``` python
from copy import deepcopy
dc_villains = [['Lex Luther', 'General Zod'], ['Joker', 'Scarecrow']]
villains = deepcopy(dc_villains)
dc_villains[1][1] = 'Pinguin'
print(villains)
```
%% Output
[['Lex Luther', 'General Zod'], ['Joker', 'Scarecrow']]
%% Cell type:markdown id: tags:
### Раздел 6. Практика: vedis и matplotlib
Есть достаточно интересный модуль vedis, который предоставляет доступ к key-value store типа Redis на диске, но при этом API этого доступа совпадает с доступом к словарю.
Решим с использованием модуля vedis [задачу о гипотезе Колатца](https://lambda-it.ru/post/26) и сделаем визуализацию при помощи matplotlib.
Для начала напишем функцию, которая из текущего числа получает следующее в последовательности:
%% Cell type:code id: tags:
``` python
def next_kolatz(x):
if x & 1:
return 3*x + 1
return x >> 1
```
%% Cell type:markdown id: tags:
Если число x является нечетным (последний разряд в двоичной системе равен единице), то мы возвращаем 3x + 1. В противном случае, мы делим число на 2 (соответствует сдвигу вправо на один разряд в двоичной системе счисления). Теперь импортируем модуль vedis. При помощи него мы будем хранить длину цепочки для чисел, которые мы уже встречали. Также напишем функцию, которая вычисляет и возвращает длину цепочки для заданного числа x, записывает ее в хранилище, а также записывает в хранилище длины цепочек для всех промежуточных чисел:
%% Cell type:code id: tags:
``` python
def get_kolatz_length(x, storage):
cur = x
try:
return int(storage.get(cur))
except KeyError as e:
pass
stack = [cur]
while True:
cur = next_kolatz(cur)
try:
length = int(storage.get(cur))
break
except KeyError as e:
pass
stack.append(cur)
for item in stack[::-1]:
length += 1
storage.set(item, length)
return int(storage.get(x))
```
%% Cell type:markdown id: tags:
Теперь напишем функцию, которая возвращает число, меньшее заданного, для которого данная цепочка максимальна и длину цепочки:
%% Cell type:code id: tags:
``` python
def get_max_kolatz_length(n, storage):
num = max(range(1, n+1), key=lambda x: get_kolatz_length(x, storage))
return num, get_kolatz_length(num, storage)
```
%% Cell type:markdown id: tags:
Теперь остается только инициализировать хранилище и испытать наши функции:
%% Cell type:code id: tags:
``` python
from vedis import Vedis
db = Vedis('storage.db')
db.set(1, 1)
print(get_max_kolatz_length(100000, db))
db.close()
```
%% Output
(77031, 351)
True
%% Cell type:markdown id: tags:
Теперь построим обычный scatter plot при помощи matplotlib:
%% Cell type:code id: tags:
``` python
import matplotlib.pyplot as plt
db = Vedis('storage.db')
X = range(1, 101)
Y = [get_kolatz_length(x, db) for x in X]
db.close()
plt.scatter(X, Y)
plt.title('Визуализация длин цепочек Колатца')
plt.xlabel('Число')
plt.ylabel('Длина цепочки')
plt.show()
```
%% Output
%% Cell type:markdown id: tags:
### Раздел 7. Домашнее задание
Решить задачи после третьей главы Саммерфилда
Загуглить гипотезу Гольдбаха
Загуглить динамическое программирование
Написать функцию, которая принимает в качестве аргумента множество и функцию и при помощи matplotlib изображает график заданной функции на множестве значений. Добавьте несколько дополнительных аргументов: например, возможность сделать одну из осей логарифмической, выбрать разные цветовые схемы, разные типы графиков и т.д.
Решить задачу, которая будет опубликована в субботу
lecture 3/lecture_3_files/lecture_3_35_0.png

9.82 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment