SlideShare una empresa de Scribd logo
1 de 35
Descargar para leer sin conexión
Лекция 5: Встроенные коллекции и модуль
collections
Сергей Лебедев
sergei.a.lebedev@gmail.com
5 октября 2015 г.
Встроенные коллекции
• Встроенных коллекций в Python немного: tuple, list, set
и dict.
• Мы уже кратко обсуждали базовые методы работы с ними.
• Создать коллекцию можно с помощью литералов или
конструктора типов:
>>> tuple(), (0, ) * 2
((), (0, 0))
>>> list(), [0] * 2
([], [0, 0])
>>> set()
{}
>>> dict(), {}
({}, {})
• Функция len возвращает длину переданной коллекции.
• elem in collection и elem not in collection
проверяют, содержится ли в коллекции элемент,
• Удалить элемент по ключу или по индексу можно с
помощью оператора del.
• О чём тут ещё можно говорить?
1 / 30
Кортеж
Кортеж и литералы
• Литералы кортежа — обычные скобки, почти всегда их
можно и нужно опускать:
>>> x, y = point
>>> date = "October", 5
• Эта рекомендация не касается одноэлементых кортежей:
>>> # Плохо
>>> xs = 42,
>>> x, = xs
>>> x
42
>>> # Лучше
>>> xs = (42, )
>>> [x] = xs
>>> x
42
2 / 30
Кортеж и слайсы
• С помощью слайсов можно выделить
подпоследовательность в любой коллекции, в частности, в
кортеже:
>>> person = ("George", "Carlin", "May", 12, 1937)
>>> name, birthday = person[:2], person[2:]
>>> name
('George', 'Carlin')
>>> birthday
('May', 12, 1937)
• Избавиться от “магических” констант помогут
именованные слайсы:
>>> NAME, BIRTHDAY = slice(2), slice(2, None)
(None, 2, None)
>>> person[NAME]
('George', 'Carlin')
>>> person[BIRTHDAY]
('May', 12, 1937)
3 / 30
Слайсы и функция reversed
• Напоминание: функция reversed принимает одну
последовательность и возвращает другую, перечисляющую
элементы первой в обратном порядке:
>>> tuple(reversed((1, 2, 3)))
(3, 2, 1)
• Эту операцию также можно выразить через слайс с
отрицательным шагом:
>>> (1, 2, 3)[::-1]
(3, 2, 1)
Вопрос
Зачем нужна “лишняя” функция reversed?
4 / 30
Конкатенация кортежей
• Кортежи можно конкатенировать с помощью бинарной
операции +. Результатом конкатенации всегда является
новый кортеж:
>>> xs, ys = (1, 2), (3, )
>>> id(xs), id(ys)
(4416359176, 4413860384)
>>> id(xs + ys)
4416309504
• Сравнение кортежей происходит в лексикографическом
порядке, причём длина учитывается, только если одна
последовательность является префиксом другой:
>>> (1, 2, 3) < (1, 2, 4)
True
>>> (1, 2, 3, 4) < (1, 2, 4)
True
>>> (1, 2) < (1, 2, 42)
True
5 / 30
collections.namedtuple
• Функция namedtuple возвращает тип кортежа,
специализированный на фиксированное множество полей:
>>> from collections import namedtuple
>>> Person = namedtuple("Person", ["name", "age"])
>>> p = Person("George", age=77)
>>> p._fields
('name', 'age')
>>> p.name, p.age
('George', 77)
• Несколько полезных методов при работе с именованными
кортежами:
>>> p._asdict()
OrderedDict([('name', 'George'), ('age', 77)])
>>> p._replace(name="Bill")
Person(name='Bill', age=77)
6 / 30
Список
Инициализация списка
• Напоминание: синтаксис инициализации создаёт список
указанной длины и заполняет его начальным значением:
>>> [0] * 2
[0, 0]
>>> [""] * 2
["", ""]
• Важно понимать, что копирование начального значения
при этом не происходит:
>>> chunks = [[0]] * 2 # матрица 2 x 1 из нулей
>>> chunks
[[0], [0]]
>>> chunks[0][0] = 42
>>> chunks
[[42], [42]]
• Как правильно инициализировать chunks?
7 / 30
Методы работы со списками: добавление элементов
• Методы append и extend добавлют в конец списка один
элемент или произвольную последовательность
соответственно:
>>> xs = [1, 2, 3]
>>> xs.append(42) # ==> [1, 2, 3, 42]
>>> xs.extend({-1, -2}) # ==> [1, 2, 3, 42, -2, -1]
• Вставить элемент перед элементом с указанным индексом
можно с помощью метода insert:
>>> xs = [1, 2, 3]
>>> xs.insert(0, 4) # ==> [4, 1, 2, 3]
>>> xs.insert(-1, 42) # ==> [4, 1, 2, 42, 3]
• Можно также заменить подпоследовательность на
элементы другой последовательности:
>>> xs = [1, 2, 3]
>>> xs[:2] = [0] * 2 # ==> [0, 0, 3]
8 / 30
Конкатенация списков
• Конкатенация списков работает аналогично конкатенации
кортежей: результатом всегда является новый список.
>>> xs, ys = [1, 2], [3]
>>> id(xs), id(ys)
(4416336136, 4416336008)
>>> id(xs + ys)
4415376136
• В отличие от кортежей списки поддерживают inplace
конкатенацию:
>>> xs += ys # ≈ xs = xs.extend(ys)
>>> id(xs)
4416336136
• Вопрос для любителей +=:
>>> xs = []
>>> def f():
... xs += [42]
...
>>> f()
9 / 30
Методы работы со списками: удаление элементов
• С помощью оператора del можно удалить не только один
элемент по его индексу, но и целую
подпоследовательность:
>>> xs = [1, 2, 3]
>>> del xs[:2]
>>> xs # ==> [3]
>>> xs = [1, 2, 3]
>>> del xs[:]
>>> xs # ==> []
• Иногда при удалении элемента по индексу может быть
удобно также получить его значение:
>>> xs = [1, 2, 3]
>>> xs.pop(1)
2
>>> xs # ==> [1, 3]
• Удалить первое вхождение элемента в списке можно с
помощью метода remove:
>>> xs = [1, 1, 0]
>>> xs.remove(1)
>>> xs # ==> [1, 0]
10 / 30
Списки и функция reversed
• Уже знакомая нам функция reversed работает со
списками:
>>> list(reversed([1, 2, 3]))
[3, 2, 1]
• Можно также перевернуть список inplace:
>>> xs = [1, 2, 3]
>>> xs.reverse()
>>> xs
[3, 2, 1]
• Обратите внимание, что в отличие от функции reversed
inlpace операция возвращает None, подсказывая
пользователю, что список был изменён.
11 / 30
Списки и функция sorted
• Аналогичные взаимоотношения у функции sorted и
метода sort1:
>>> xs = [3, 2, 1]
>>> sorted(xs), xs
([1, 2, 3], [3, 2, 1])
>>> xs.sort()
>>> xs
[1, 2, 3]
• Функции sorted и методу sort можно опционально
указать направление сортировки, а также функцию-ключ:
>>> xs = [3, 2, 1]
>>> xs.sort(key=lambda x: x % 2, reverse=True)
>>> xs
[3, 1, 2]
1
CPython использует довольно хитрый алгоритм сортировки Timsort за
авторством Тима Питерса. В репозитории CPython можно найти документ,
подробно описывающий мотивацию и основные идеи Timsort:
http://bugs.python.org/file4451/timsort.txt.
12 / 30
Список — это стек, список – это очередь!
>>> stack = []
>>> stack.append(1)
>>> stack.append(2)
>>> stack.pop()
2
>>> stack
[1]
>>> q = []
>>> q.append(1)
>>> q.append(2)
>>> q.pop(0)
1
>>> q
[2]
Вопрос
В чём проблема с q.pop(0)?
13 / 30
collections.deque
• Тип deque реализует двустороннюю очередь:
>>> from collections import deque
>>> q = deque()
• Добавление и удаление элемента с обеих сторон очереди
работает за константное время, индексирование — за
время, линейное от размера очереди.
• Резюме операций c deque:
>>> q = deque([1, 2, 3])
>>> q.appendleft(0)
>>> q
deque([0, 1, 2, 3])
>>> q.append(4)
>>> q
deque([0, 1, 2, 3, 4])
>>> q.popleft()
0
>>> q[0]
1
14 / 30
Несколько слов об ограниченной deque
• Конструктор deque принимает опциональный аргумент
maxlen, ограничивающий максимальную длину очереди.
• При добавлении элемента к ограниченной очереди
лишние элементы “вываливаются” с противоположной
стороны:
>>> q = deque([1, 2], maxlen=2)
>>> q.appendleft(0)
>>> q
deque([0, 1], maxlen=2)
>>> q.append(2)
>>> q
deque([1, 2], maxlen=2)
15 / 30
Множество
Методы работы с множествами: базовые
• Базовые операции при работе с множествами:
>>> xs, ys, zs = {1, 2}, {2, 3}, {3, 4}
>>> set.union(xs, ys, zs) # xs | ys | zs
{1, 2, 3, 4}
>>> set.intersection(xs, ys, zs) # xs & ys & zs
set()
>>> set.difference(xs, ys, zs) # xs - ys - zs
{1}
• Операции сравнения множеств:
>>> xs.isdisjoint(ys)
False
>>> xs <= ys # xs ⊆ ys
False
>>> xs < xs # xs ⊂ xs
False
>>> xs | ys >= xs # xs ∪ ys ⊇ xs
True
16 / 30
Методы работы с множествами: добавление элементов
• Добавить один элемент в множестве можно с помощью
метода add, добавить последовательность элементов — с
помощью метода update:
>>> seen = set()
>>> seen.add(42)
>>> seen
{42}
>>> seen.update([1, 2])
>>> seen
{1, 2, 42}
• Метод update принимает произвольное количество
аргументов:
>>> seen.update([], [1], [2], [3])
>>> seen
{1, 2, 42, 3}
17 / 30
Методы работы с множествами: удаление элементов
• Метод remove удаляет из множества существующий
элемент или поднимает исключение, если элемент во
множестве не содержится:
>>> seen = {1, 2, 3}
>>> seen.remove(3)
>>> seen
{1, 2}
>>> seen.remove(100500)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 100500
• В отличие от метода remove метод discard удаляет
элемент, только если он содержится во множестве:
>>> seen.discard(100500)
>>> seen
{1, 2}
• Удалить все элементы из множества можно с помощью
метода clear.
18 / 30
Множество и хеширование
• Напоминание: множество в Python — это хеш-сет, то есть
оно может содержать только элементы, которые можно
захешировать.
• Можно ли сделать множество множеств?
>>> {set(), set()}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
• Тип frozenset описывает неизменяемое множество:
>>> {frozenset(), frozenset()}
{frozenset()}
Капитан сообщает
Объекты типа frozenset поддерживают все операции типа set
кроме операций добавления и удаления элементов.
19 / 30
Словарь
Словарь и конструктор dict
• Конструктор dict позволяет создать словарь без
использования литералов:
>>> d = dict(foo="bar")
>>> dict(d) # (shallow) копия
{'foo': 'bar'}
>>> dict(d, boo="baz") # копирование с добавлением ключей
{'boo': 'baz', 'foo': 'bar'}
• Можно также сконструировать словарь из
последовательности ключей и значения по умолчанию:
>>> dict.fromkeys(["foo", "bar"])
{'foo': None, 'bar': None}
>>> dict.fromkeys("abcd", 0)
{'d': 0, 'a': 0, 'b': 0, 'c': 0}
Вопрос
Эквивалентны ли эти два выражения?
dict.fromkeys("abcd", []) {ch: [] for ch in "abcd"}
20 / 30
Методы работы со словарями: проекции
• Методы keys, values и items возвращают проекции
содержимого словаря:
>>> d = dict.fromkeys(["foo", "bar"], 42)
>>> d.keys()
dict_keys(['foo', 'bar'])
>>> d.values()
dict_values([42, 42])
>>> d.items()
dict_items([('foo', 42), ('bar', 42)])
• Проекции поддерживают стандратные операции
последовательности:
>>> len(d.items())
2
>>> 42 in d.values()
True
• Проекция keys дополнительно реализует некоторые
операции множества:
>>> d.keys() & {"foo"}
{'foo'}
21 / 30
Проекции словаря и цикл for
• Проекции можно использовать для итерации в цикле for
или генераторе:
>>> {v for v in d.values()}
{42}
• Модифицировать содержимое словаря в процессе
итерации нельзя:
>>> for k in d:
... del d[k]
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
• Если очень хочется, можно сделать копию проекции и
итерироваться по ней:
>>> for k in set(d):
... del d[k]
...
>>> d
{}
22 / 30
Методы работы со словарями: get
Напоминание: получить значение элемента по ключу можно с
помощью синтаксиса d[key] или метода get:
>>> d = {"foo": "bar"}
>>> d["foo"]
'bar'
>>> d["boo"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'boo'
>>> d.get("boo", 42)
42
Вопрос
Зачем нужен метод get, если можно написать
>>> if key not in d:
... value = default
... else:
... value = d[key]
23 / 30
Методы работы со словарями: добавление элементов
• Напоминание: записать значение по ключу можно с
помощью синтаксиса d[key] = value.
• Метод setdefault позволяет за один запрос к хеш-таблице
проверить, есть ли в ней значение по некоторому ключу и,
если значения нет, установить его в заданное.
>>> d = {"foo": "bar"}
>>> d.setdefault("foo", "???")
'bar'
>>> d.setdefault("boo", 42)
42
>>> d
{'boo': 42, 'foo': 'bar'}
• Метод update добавляет словарь элементы переданной
последовательности пар или словаря:
>>> d = {}
>>> d.update([("foo", "bar")], boo=42)
>>> d
{'boo': 42, 'foo': 'bar'}
24 / 30
Методы работы со словарями: удаление элементов
• Напоминение: удалить значение по ключу можно с
помощью оператора del d[key].
• Метод pop удаляет значение по ключу и возвращает его в
качестве результата, а метод clear удаляет из словаря все
значения:
>>> d = {"foo": "bar", "boo": 42}
>>> d.pop("foo")
'bar'
>>> d
{'boo': 42}
>>> d.clear()
>>> d
{}
25 / 30
collections.defaultdict
• Допустим, мы хотим хранить направленный граф в виде
“списка” смежности:
>>> g = {"a": {"b"}, "b": {"c"}}
>>> g["a"]
{'b'}
• Как добавить в граф ребра ("b", "a") и ("c", "a")?
>>> g["b"].add("a")
>>> g["c"].add("a")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'c'
• Избавит от боли defaultdict — словарь с
функцией-инициализатором:
>>> from collections import defaultdict
>>> g = defaultdict(set, **{"a": {"b"}, "b": {"c"}})
>>> g["c"].add("a")
>>> g
defaultdict(<class 'set'>,
{'b': {'c'}, 'c': {'a'}, 'a': {'b'}})
26 / 30
collections.OrderedDict2
• Порядок ключей в обычном словаре не определён:
>>> d = dict([("foo", "bar"), ("boo", 42)])
>>> list(d)
['boo', 'foo']
• OrderedDict — словарь с ключами, упорядоченными по
времени добавления:
>>> from collections import OrderedDict
>>> d = OrderedDict([("foo", "bar"), ("boo", 42)])
>>> list(d)
['foo', 'boo']
• Изменение значения по ключу не влияет на порядок
ключей в словаре:
>>> d["boo"] = "???" # не изменит порядок ключей
>>> d["bar"] = "???"
>>> list(d)
['foo', 'boo', 'bar']
2
http://python.org/dev/peps/pep-0372
27 / 30
collections.Counter
• Тип Counter — это специализация словаря для подсчёта
объектов, которые можно захешировать:
>>> from collections import Counter
>>> c = Counter(["foo", "foo", "foo", "bar"])
>>> c["foo"] += 1
>>> c
Counter({'foo': 4, 'bar': 1})
• Счётчик поддерживает все методы словаря, а также
реализует несколько дополнительных:
>>> c.pop("foo")
4
>>> c["boo"] # не поднимает исключение
0
28 / 30
Методы работы со счётчиком
• Метод elements перечисляет элементы счётчика в
произвольном порядке. Элементы, для которых частота
равна нулю или отрицательна, игнорируются:
>>> c = Counter(foo=4, bar=-1)
>>> list(c.elements())
['foo', 'foo', 'foo', 'foo']
• Метод most_common возвращает заданное число самых
частых элементов:
>>> c.most_common(1)
[('foo', 4)]
• Методы substract и update позволяют поэлементно
обновить значения счётчика:
>>> c.update(["bar"])
>>> c
Counter({'foo': 4, 'bar': 0})
>>> c.subtract({"foo": 2})
>>> c
Counter({'foo': 2, 'bar': 0})
29 / 30
Счётчик как мультимножество
>>> c1 = Counter(foo=4, bar=-1)
>>> c2 = Counter(foo=2, bar=2)
>>> c1 + c2 # c1[k] + c2[k]
Counter({'foo': 6, 'bar': 1})
>>> c1 - c2 # c1[k] - c2[k]
Counter({'foo': 2})
>>> c1 & c2 # min(c1[k], c2[k])
Counter({'foo': 2})
>>> c1 | c2 # max(c1[k], c2[k])
Counter({'foo': 4, 'bar': 2})
Замечание
Результат любой из бинарных операций всегда содержит
только ключи с положительными частотами.
30 / 30

Más contenido relacionado

La actualidad más candente

Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"
Python Meetup
 

La actualidad más candente (17)

Лекция 8. Итераторы, генераторы и модуль itertools.
 Лекция 8. Итераторы, генераторы и модуль itertools. Лекция 8. Итераторы, генераторы и модуль itertools.
Лекция 8. Итераторы, генераторы и модуль itertools.
 
Лекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILЛекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GIL
 
Лекция 9. Модули, пакеты и система импорта.
Лекция 9. Модули, пакеты и система импорта.Лекция 9. Модули, пакеты и система импорта.
Лекция 9. Модули, пакеты и система импорта.
 
Лекция 11. Тестирование.
Лекция 11. Тестирование.Лекция 11. Тестирование.
Лекция 11. Тестирование.
 
Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3
 
Красота и изящность стандартной библиотеки Python
Красота и изящность стандартной библиотеки PythonКрасота и изящность стандартной библиотеки Python
Красота и изящность стандартной библиотеки Python
 
Декораторы в Python и их практическое использование
Декораторы в Python и их практическое использование Декораторы в Python и их практическое использование
Декораторы в Python и их практическое использование
 
Производительность в Django
Производительность в DjangoПроизводительность в Django
Производительность в Django
 
Python и его тормоза
Python и его тормозаPython и его тормоза
Python и его тормоза
 
Профилирование и отладка Django
Профилирование и отладка DjangoПрофилирование и отладка Django
Профилирование и отладка Django
 
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
 
Pyton – пробуем функциональный стиль
Pyton – пробуем функциональный стильPyton – пробуем функциональный стиль
Pyton – пробуем функциональный стиль
 
C#. От основ к эффективному коду
C#. От основ к эффективному кодуC#. От основ к эффективному коду
C#. От основ к эффективному коду
 
Оптимизация производительности Python
Оптимизация производительности PythonОптимизация производительности Python
Оптимизация производительности Python
 
Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"
 
Магия метаклассов
Магия метаклассовМагия метаклассов
Магия метаклассов
 
Магия в Python: Дескрипторы. Что это?
Магия в Python: Дескрипторы. Что это?Магия в Python: Дескрипторы. Что это?
Магия в Python: Дескрипторы. Что это?
 

Destacado (7)

09 - Практика UML. Use Case диаграммы
09 - Практика UML. Use Case диаграммы09 - Практика UML. Use Case диаграммы
09 - Практика UML. Use Case диаграммы
 
04 - Практика UML. Описание прецедентов
04 - Практика UML. Описание прецедентов04 - Практика UML. Описание прецедентов
04 - Практика UML. Описание прецедентов
 
02 - Практика UML. Уровни приложения
02 - Практика UML. Уровни приложения02 - Практика UML. Уровни приложения
02 - Практика UML. Уровни приложения
 
01 - Практика UML. Нужен ли UML?
01 - Практика UML. Нужен ли UML?01 - Практика UML. Нужен ли UML?
01 - Практика UML. Нужен ли UML?
 
12 - Практика UML. Создание wireframe
12 - Практика UML. Создание wireframe12 - Практика UML. Создание wireframe
12 - Практика UML. Создание wireframe
 
13 - Практика UML. Переход к разработке
13 - Практика UML. Переход к разработке13 - Практика UML. Переход к разработке
13 - Практика UML. Переход к разработке
 
03 - Практика UML. Прецеденты
03 - Практика UML. Прецеденты03 - Практика UML. Прецеденты
03 - Практика UML. Прецеденты
 

Similar a Лекция 5. Встроенные коллекции и модуль collections.

MySQL+HandlerSocket=NoSQL
MySQL+HandlerSocket=NoSQL MySQL+HandlerSocket=NoSQL
MySQL+HandlerSocket=NoSQL
Sergey Xek
 
CodeFest 2013. Аверин С. — MySQL+HandlerSocket=NoSQL
CodeFest 2013. Аверин С. — MySQL+HandlerSocket=NoSQLCodeFest 2013. Аверин С. — MySQL+HandlerSocket=NoSQL
CodeFest 2013. Аверин С. — MySQL+HandlerSocket=NoSQL
CodeFest
 
Java осень 2013 лекция 2
Java осень 2013 лекция 2Java осень 2013 лекция 2
Java осень 2013 лекция 2
Technopark
 
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
Ontico
 
Join the python_side
Join the python_sideJoin the python_side
Join the python_side
Paul Dmitryev
 
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
 То, что вы хотели знать о HandlerSocket, но не смогли нагуглить То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
Sergey Xek
 

Similar a Лекция 5. Встроенные коллекции и модуль collections. (20)

MySQL+HandlerSocket=NoSQL
MySQL+HandlerSocket=NoSQL MySQL+HandlerSocket=NoSQL
MySQL+HandlerSocket=NoSQL
 
Learning from Swift sources, Иван Сметанин
Learning from Swift sources, Иван СметанинLearning from Swift sources, Иван Сметанин
Learning from Swift sources, Иван Сметанин
 
CodeFest 2013. Аверин С. — MySQL+HandlerSocket=NoSQL
CodeFest 2013. Аверин С. — MySQL+HandlerSocket=NoSQLCodeFest 2013. Аверин С. — MySQL+HandlerSocket=NoSQL
CodeFest 2013. Аверин С. — MySQL+HandlerSocket=NoSQL
 
Sergii Tsypanov "Performance 1001 Tips"
Sergii Tsypanov "Performance 1001 Tips"Sergii Tsypanov "Performance 1001 Tips"
Sergii Tsypanov "Performance 1001 Tips"
 
Python dict: прошлое, настоящее, будущее
Python dict: прошлое, настоящее, будущееPython dict: прошлое, настоящее, будущее
Python dict: прошлое, настоящее, будущее
 
Java осень 2013 лекция 2
Java осень 2013 лекция 2Java осень 2013 лекция 2
Java осень 2013 лекция 2
 
Лекция о языке программирования Haskell
Лекция о языке программирования HaskellЛекция о языке программирования Haskell
Лекция о языке программирования Haskell
 
Сергей Аверин, То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
Сергей Аверин, То, что вы хотели знать о HandlerSocket, но не смогли нагуглитьСергей Аверин, То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
Сергей Аверин, То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
 
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
То, что вы хотели знать о HandlerSocket, но не смогли нагуглитьТо, что вы хотели знать о HandlerSocket, но не смогли нагуглить
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
 
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
 
2014-11-01 03 Николай Линкер. Open your clojure
2014-11-01 03 Николай Линкер. Open your clojure2014-11-01 03 Николай Линкер. Open your clojure
2014-11-01 03 Николай Линкер. Open your clojure
 
Мир Python функционалим с помощью библиотек
Мир Python  функционалим с помощью библиотекМир Python  функционалим с помощью библиотек
Мир Python функционалим с помощью библиотек
 
Основы языка R
Основы языка RОсновы языка R
Основы языка R
 
Lambdas in java 8
Lambdas in java 8Lambdas in java 8
Lambdas in java 8
 
Иван Фролков
Иван ФролковИван Фролков
Иван Фролков
 
Функциональное программирование на F#
Функциональное программирование на F#Функциональное программирование на F#
Функциональное программирование на F#
 
C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 01.C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 01.
 
Основы Python. Функции
Основы Python. ФункцииОсновы Python. Функции
Основы Python. Функции
 
Join the python_side
Join the python_sideJoin the python_side
Join the python_side
 
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
 То, что вы хотели знать о HandlerSocket, но не смогли нагуглить То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить
 

Más de Roman Brovko

Bare metal training_06_I2C
Bare metal training_06_I2CBare metal training_06_I2C
Bare metal training_06_I2C
Roman Brovko
 
Bare metal training_05_uart
Bare metal training_05_uartBare metal training_05_uart
Bare metal training_05_uart
Roman Brovko
 
подготовка рабочего окружения
подготовка рабочего окруженияподготовка рабочего окружения
подготовка рабочего окружения
Roman Brovko
 

Más de Roman Brovko (20)

Individual task Networking
Individual task NetworkingIndividual task Networking
Individual task Networking
 
Networking essentials lect3
Networking essentials lect3Networking essentials lect3
Networking essentials lect3
 
Gl embedded starterkit_ethernet
Gl embedded starterkit_ethernetGl embedded starterkit_ethernet
Gl embedded starterkit_ethernet
 
Networking essentials lect2
Networking essentials lect2Networking essentials lect2
Networking essentials lect2
 
Networking essentials lect1
Networking essentials lect1Networking essentials lect1
Networking essentials lect1
 
Bare metal training_07_spi_flash
Bare metal training_07_spi_flashBare metal training_07_spi_flash
Bare metal training_07_spi_flash
 
Bare metal training_06_I2C
Bare metal training_06_I2CBare metal training_06_I2C
Bare metal training_06_I2C
 
Glesk worshop
Glesk worshopGlesk worshop
Glesk worshop
 
Bare metal training_05_uart
Bare metal training_05_uartBare metal training_05_uart
Bare metal training_05_uart
 
Bare metal training_04_adc_temp_sensor
Bare metal training_04_adc_temp_sensorBare metal training_04_adc_temp_sensor
Bare metal training_04_adc_temp_sensor
 
Bare metal training_03_timers_pwm
Bare metal training_03_timers_pwmBare metal training_03_timers_pwm
Bare metal training_03_timers_pwm
 
Bare metal training_02_le_ds_and_buttons
Bare metal training_02_le_ds_and_buttonsBare metal training_02_le_ds_and_buttons
Bare metal training_02_le_ds_and_buttons
 
Bare metal training_01_hello_world
Bare metal training_01_hello_worldBare metal training_01_hello_world
Bare metal training_01_hello_world
 
Bare metal training_00_prerequisites
Bare metal training_00_prerequisitesBare metal training_00_prerequisites
Bare metal training_00_prerequisites
 
C language lect_23_advanced
C language lect_23_advancedC language lect_23_advanced
C language lect_23_advanced
 
C language lect_22_advanced
C language lect_22_advancedC language lect_22_advanced
C language lect_22_advanced
 
C language lect_21_advanced
C language lect_21_advancedC language lect_21_advanced
C language lect_21_advanced
 
подготовка рабочего окружения
подготовка рабочего окруженияподготовка рабочего окружения
подготовка рабочего окружения
 
C language lect_20_advanced
C language lect_20_advancedC language lect_20_advanced
C language lect_20_advanced
 
C language lect_19_basics
C language lect_19_basicsC language lect_19_basics
C language lect_19_basics
 

Лекция 5. Встроенные коллекции и модуль collections.

  • 1. Лекция 5: Встроенные коллекции и модуль collections Сергей Лебедев sergei.a.lebedev@gmail.com 5 октября 2015 г.
  • 2. Встроенные коллекции • Встроенных коллекций в Python немного: tuple, list, set и dict. • Мы уже кратко обсуждали базовые методы работы с ними. • Создать коллекцию можно с помощью литералов или конструктора типов: >>> tuple(), (0, ) * 2 ((), (0, 0)) >>> list(), [0] * 2 ([], [0, 0]) >>> set() {} >>> dict(), {} ({}, {}) • Функция len возвращает длину переданной коллекции. • elem in collection и elem not in collection проверяют, содержится ли в коллекции элемент, • Удалить элемент по ключу или по индексу можно с помощью оператора del. • О чём тут ещё можно говорить? 1 / 30
  • 4. Кортеж и литералы • Литералы кортежа — обычные скобки, почти всегда их можно и нужно опускать: >>> x, y = point >>> date = "October", 5 • Эта рекомендация не касается одноэлементых кортежей: >>> # Плохо >>> xs = 42, >>> x, = xs >>> x 42 >>> # Лучше >>> xs = (42, ) >>> [x] = xs >>> x 42 2 / 30
  • 5. Кортеж и слайсы • С помощью слайсов можно выделить подпоследовательность в любой коллекции, в частности, в кортеже: >>> person = ("George", "Carlin", "May", 12, 1937) >>> name, birthday = person[:2], person[2:] >>> name ('George', 'Carlin') >>> birthday ('May', 12, 1937) • Избавиться от “магических” констант помогут именованные слайсы: >>> NAME, BIRTHDAY = slice(2), slice(2, None) (None, 2, None) >>> person[NAME] ('George', 'Carlin') >>> person[BIRTHDAY] ('May', 12, 1937) 3 / 30
  • 6. Слайсы и функция reversed • Напоминание: функция reversed принимает одну последовательность и возвращает другую, перечисляющую элементы первой в обратном порядке: >>> tuple(reversed((1, 2, 3))) (3, 2, 1) • Эту операцию также можно выразить через слайс с отрицательным шагом: >>> (1, 2, 3)[::-1] (3, 2, 1) Вопрос Зачем нужна “лишняя” функция reversed? 4 / 30
  • 7. Конкатенация кортежей • Кортежи можно конкатенировать с помощью бинарной операции +. Результатом конкатенации всегда является новый кортеж: >>> xs, ys = (1, 2), (3, ) >>> id(xs), id(ys) (4416359176, 4413860384) >>> id(xs + ys) 4416309504 • Сравнение кортежей происходит в лексикографическом порядке, причём длина учитывается, только если одна последовательность является префиксом другой: >>> (1, 2, 3) < (1, 2, 4) True >>> (1, 2, 3, 4) < (1, 2, 4) True >>> (1, 2) < (1, 2, 42) True 5 / 30
  • 8. collections.namedtuple • Функция namedtuple возвращает тип кортежа, специализированный на фиксированное множество полей: >>> from collections import namedtuple >>> Person = namedtuple("Person", ["name", "age"]) >>> p = Person("George", age=77) >>> p._fields ('name', 'age') >>> p.name, p.age ('George', 77) • Несколько полезных методов при работе с именованными кортежами: >>> p._asdict() OrderedDict([('name', 'George'), ('age', 77)]) >>> p._replace(name="Bill") Person(name='Bill', age=77) 6 / 30
  • 10. Инициализация списка • Напоминание: синтаксис инициализации создаёт список указанной длины и заполняет его начальным значением: >>> [0] * 2 [0, 0] >>> [""] * 2 ["", ""] • Важно понимать, что копирование начального значения при этом не происходит: >>> chunks = [[0]] * 2 # матрица 2 x 1 из нулей >>> chunks [[0], [0]] >>> chunks[0][0] = 42 >>> chunks [[42], [42]] • Как правильно инициализировать chunks? 7 / 30
  • 11. Методы работы со списками: добавление элементов • Методы append и extend добавлют в конец списка один элемент или произвольную последовательность соответственно: >>> xs = [1, 2, 3] >>> xs.append(42) # ==> [1, 2, 3, 42] >>> xs.extend({-1, -2}) # ==> [1, 2, 3, 42, -2, -1] • Вставить элемент перед элементом с указанным индексом можно с помощью метода insert: >>> xs = [1, 2, 3] >>> xs.insert(0, 4) # ==> [4, 1, 2, 3] >>> xs.insert(-1, 42) # ==> [4, 1, 2, 42, 3] • Можно также заменить подпоследовательность на элементы другой последовательности: >>> xs = [1, 2, 3] >>> xs[:2] = [0] * 2 # ==> [0, 0, 3] 8 / 30
  • 12. Конкатенация списков • Конкатенация списков работает аналогично конкатенации кортежей: результатом всегда является новый список. >>> xs, ys = [1, 2], [3] >>> id(xs), id(ys) (4416336136, 4416336008) >>> id(xs + ys) 4415376136 • В отличие от кортежей списки поддерживают inplace конкатенацию: >>> xs += ys # ≈ xs = xs.extend(ys) >>> id(xs) 4416336136 • Вопрос для любителей +=: >>> xs = [] >>> def f(): ... xs += [42] ... >>> f() 9 / 30
  • 13. Методы работы со списками: удаление элементов • С помощью оператора del можно удалить не только один элемент по его индексу, но и целую подпоследовательность: >>> xs = [1, 2, 3] >>> del xs[:2] >>> xs # ==> [3] >>> xs = [1, 2, 3] >>> del xs[:] >>> xs # ==> [] • Иногда при удалении элемента по индексу может быть удобно также получить его значение: >>> xs = [1, 2, 3] >>> xs.pop(1) 2 >>> xs # ==> [1, 3] • Удалить первое вхождение элемента в списке можно с помощью метода remove: >>> xs = [1, 1, 0] >>> xs.remove(1) >>> xs # ==> [1, 0] 10 / 30
  • 14. Списки и функция reversed • Уже знакомая нам функция reversed работает со списками: >>> list(reversed([1, 2, 3])) [3, 2, 1] • Можно также перевернуть список inplace: >>> xs = [1, 2, 3] >>> xs.reverse() >>> xs [3, 2, 1] • Обратите внимание, что в отличие от функции reversed inlpace операция возвращает None, подсказывая пользователю, что список был изменён. 11 / 30
  • 15. Списки и функция sorted • Аналогичные взаимоотношения у функции sorted и метода sort1: >>> xs = [3, 2, 1] >>> sorted(xs), xs ([1, 2, 3], [3, 2, 1]) >>> xs.sort() >>> xs [1, 2, 3] • Функции sorted и методу sort можно опционально указать направление сортировки, а также функцию-ключ: >>> xs = [3, 2, 1] >>> xs.sort(key=lambda x: x % 2, reverse=True) >>> xs [3, 1, 2] 1 CPython использует довольно хитрый алгоритм сортировки Timsort за авторством Тима Питерса. В репозитории CPython можно найти документ, подробно описывающий мотивацию и основные идеи Timsort: http://bugs.python.org/file4451/timsort.txt. 12 / 30
  • 16. Список — это стек, список – это очередь! >>> stack = [] >>> stack.append(1) >>> stack.append(2) >>> stack.pop() 2 >>> stack [1] >>> q = [] >>> q.append(1) >>> q.append(2) >>> q.pop(0) 1 >>> q [2] Вопрос В чём проблема с q.pop(0)? 13 / 30
  • 17. collections.deque • Тип deque реализует двустороннюю очередь: >>> from collections import deque >>> q = deque() • Добавление и удаление элемента с обеих сторон очереди работает за константное время, индексирование — за время, линейное от размера очереди. • Резюме операций c deque: >>> q = deque([1, 2, 3]) >>> q.appendleft(0) >>> q deque([0, 1, 2, 3]) >>> q.append(4) >>> q deque([0, 1, 2, 3, 4]) >>> q.popleft() 0 >>> q[0] 1 14 / 30
  • 18. Несколько слов об ограниченной deque • Конструктор deque принимает опциональный аргумент maxlen, ограничивающий максимальную длину очереди. • При добавлении элемента к ограниченной очереди лишние элементы “вываливаются” с противоположной стороны: >>> q = deque([1, 2], maxlen=2) >>> q.appendleft(0) >>> q deque([0, 1], maxlen=2) >>> q.append(2) >>> q deque([1, 2], maxlen=2) 15 / 30
  • 20. Методы работы с множествами: базовые • Базовые операции при работе с множествами: >>> xs, ys, zs = {1, 2}, {2, 3}, {3, 4} >>> set.union(xs, ys, zs) # xs | ys | zs {1, 2, 3, 4} >>> set.intersection(xs, ys, zs) # xs & ys & zs set() >>> set.difference(xs, ys, zs) # xs - ys - zs {1} • Операции сравнения множеств: >>> xs.isdisjoint(ys) False >>> xs <= ys # xs ⊆ ys False >>> xs < xs # xs ⊂ xs False >>> xs | ys >= xs # xs ∪ ys ⊇ xs True 16 / 30
  • 21. Методы работы с множествами: добавление элементов • Добавить один элемент в множестве можно с помощью метода add, добавить последовательность элементов — с помощью метода update: >>> seen = set() >>> seen.add(42) >>> seen {42} >>> seen.update([1, 2]) >>> seen {1, 2, 42} • Метод update принимает произвольное количество аргументов: >>> seen.update([], [1], [2], [3]) >>> seen {1, 2, 42, 3} 17 / 30
  • 22. Методы работы с множествами: удаление элементов • Метод remove удаляет из множества существующий элемент или поднимает исключение, если элемент во множестве не содержится: >>> seen = {1, 2, 3} >>> seen.remove(3) >>> seen {1, 2} >>> seen.remove(100500) Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 100500 • В отличие от метода remove метод discard удаляет элемент, только если он содержится во множестве: >>> seen.discard(100500) >>> seen {1, 2} • Удалить все элементы из множества можно с помощью метода clear. 18 / 30
  • 23. Множество и хеширование • Напоминание: множество в Python — это хеш-сет, то есть оно может содержать только элементы, которые можно захешировать. • Можно ли сделать множество множеств? >>> {set(), set()} Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'set' • Тип frozenset описывает неизменяемое множество: >>> {frozenset(), frozenset()} {frozenset()} Капитан сообщает Объекты типа frozenset поддерживают все операции типа set кроме операций добавления и удаления элементов. 19 / 30
  • 25. Словарь и конструктор dict • Конструктор dict позволяет создать словарь без использования литералов: >>> d = dict(foo="bar") >>> dict(d) # (shallow) копия {'foo': 'bar'} >>> dict(d, boo="baz") # копирование с добавлением ключей {'boo': 'baz', 'foo': 'bar'} • Можно также сконструировать словарь из последовательности ключей и значения по умолчанию: >>> dict.fromkeys(["foo", "bar"]) {'foo': None, 'bar': None} >>> dict.fromkeys("abcd", 0) {'d': 0, 'a': 0, 'b': 0, 'c': 0} Вопрос Эквивалентны ли эти два выражения? dict.fromkeys("abcd", []) {ch: [] for ch in "abcd"} 20 / 30
  • 26. Методы работы со словарями: проекции • Методы keys, values и items возвращают проекции содержимого словаря: >>> d = dict.fromkeys(["foo", "bar"], 42) >>> d.keys() dict_keys(['foo', 'bar']) >>> d.values() dict_values([42, 42]) >>> d.items() dict_items([('foo', 42), ('bar', 42)]) • Проекции поддерживают стандратные операции последовательности: >>> len(d.items()) 2 >>> 42 in d.values() True • Проекция keys дополнительно реализует некоторые операции множества: >>> d.keys() & {"foo"} {'foo'} 21 / 30
  • 27. Проекции словаря и цикл for • Проекции можно использовать для итерации в цикле for или генераторе: >>> {v for v in d.values()} {42} • Модифицировать содержимое словаря в процессе итерации нельзя: >>> for k in d: ... del d[k] ... Traceback (most recent call last): File "<stdin>", line 1, in <module> RuntimeError: dictionary changed size during iteration • Если очень хочется, можно сделать копию проекции и итерироваться по ней: >>> for k in set(d): ... del d[k] ... >>> d {} 22 / 30
  • 28. Методы работы со словарями: get Напоминание: получить значение элемента по ключу можно с помощью синтаксиса d[key] или метода get: >>> d = {"foo": "bar"} >>> d["foo"] 'bar' >>> d["boo"] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'boo' >>> d.get("boo", 42) 42 Вопрос Зачем нужен метод get, если можно написать >>> if key not in d: ... value = default ... else: ... value = d[key] 23 / 30
  • 29. Методы работы со словарями: добавление элементов • Напоминание: записать значение по ключу можно с помощью синтаксиса d[key] = value. • Метод setdefault позволяет за один запрос к хеш-таблице проверить, есть ли в ней значение по некоторому ключу и, если значения нет, установить его в заданное. >>> d = {"foo": "bar"} >>> d.setdefault("foo", "???") 'bar' >>> d.setdefault("boo", 42) 42 >>> d {'boo': 42, 'foo': 'bar'} • Метод update добавляет словарь элементы переданной последовательности пар или словаря: >>> d = {} >>> d.update([("foo", "bar")], boo=42) >>> d {'boo': 42, 'foo': 'bar'} 24 / 30
  • 30. Методы работы со словарями: удаление элементов • Напоминение: удалить значение по ключу можно с помощью оператора del d[key]. • Метод pop удаляет значение по ключу и возвращает его в качестве результата, а метод clear удаляет из словаря все значения: >>> d = {"foo": "bar", "boo": 42} >>> d.pop("foo") 'bar' >>> d {'boo': 42} >>> d.clear() >>> d {} 25 / 30
  • 31. collections.defaultdict • Допустим, мы хотим хранить направленный граф в виде “списка” смежности: >>> g = {"a": {"b"}, "b": {"c"}} >>> g["a"] {'b'} • Как добавить в граф ребра ("b", "a") и ("c", "a")? >>> g["b"].add("a") >>> g["c"].add("a") Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'c' • Избавит от боли defaultdict — словарь с функцией-инициализатором: >>> from collections import defaultdict >>> g = defaultdict(set, **{"a": {"b"}, "b": {"c"}}) >>> g["c"].add("a") >>> g defaultdict(<class 'set'>, {'b': {'c'}, 'c': {'a'}, 'a': {'b'}}) 26 / 30
  • 32. collections.OrderedDict2 • Порядок ключей в обычном словаре не определён: >>> d = dict([("foo", "bar"), ("boo", 42)]) >>> list(d) ['boo', 'foo'] • OrderedDict — словарь с ключами, упорядоченными по времени добавления: >>> from collections import OrderedDict >>> d = OrderedDict([("foo", "bar"), ("boo", 42)]) >>> list(d) ['foo', 'boo'] • Изменение значения по ключу не влияет на порядок ключей в словаре: >>> d["boo"] = "???" # не изменит порядок ключей >>> d["bar"] = "???" >>> list(d) ['foo', 'boo', 'bar'] 2 http://python.org/dev/peps/pep-0372 27 / 30
  • 33. collections.Counter • Тип Counter — это специализация словаря для подсчёта объектов, которые можно захешировать: >>> from collections import Counter >>> c = Counter(["foo", "foo", "foo", "bar"]) >>> c["foo"] += 1 >>> c Counter({'foo': 4, 'bar': 1}) • Счётчик поддерживает все методы словаря, а также реализует несколько дополнительных: >>> c.pop("foo") 4 >>> c["boo"] # не поднимает исключение 0 28 / 30
  • 34. Методы работы со счётчиком • Метод elements перечисляет элементы счётчика в произвольном порядке. Элементы, для которых частота равна нулю или отрицательна, игнорируются: >>> c = Counter(foo=4, bar=-1) >>> list(c.elements()) ['foo', 'foo', 'foo', 'foo'] • Метод most_common возвращает заданное число самых частых элементов: >>> c.most_common(1) [('foo', 4)] • Методы substract и update позволяют поэлементно обновить значения счётчика: >>> c.update(["bar"]) >>> c Counter({'foo': 4, 'bar': 0}) >>> c.subtract({"foo": 2}) >>> c Counter({'foo': 2, 'bar': 0}) 29 / 30
  • 35. Счётчик как мультимножество >>> c1 = Counter(foo=4, bar=-1) >>> c2 = Counter(foo=2, bar=2) >>> c1 + c2 # c1[k] + c2[k] Counter({'foo': 6, 'bar': 1}) >>> c1 - c2 # c1[k] - c2[k] Counter({'foo': 2}) >>> c1 & c2 # min(c1[k], c2[k]) Counter({'foo': 2}) >>> c1 | c2 # max(c1[k], c2[k]) Counter({'foo': 4, 'bar': 2}) Замечание Результат любой из бинарных операций всегда содержит только ключи с положительными частотами. 30 / 30