Python 3 defaultdict list

Счётчик (Counter)

Не изобретать велосипед, или Обзор модуля collections в Python

Одна из распространённых задач, для которой начинающие питонисты придумывают собственные решения, – подсчёт элементов последовательности: списка, строки символов и т. д.

Если нужно что-то посчитать, определить количество вхождений или наиболее (наименее) часто встречающихся элементов, используйте объекты класса Counter . Создаются они с помощью конструктора collections.Counter() .

Функция принимает итерируемый аргумент и возвращает словарь, в котором ключами служат индивидуальные элементы, а значениями – количества повторений элемента в переданной последовательности. Посчитаем, сколько раз встречается каждая буква в слове «абракадабра»:

Не изобретать велосипед, или Обзор модуля collections в Python

Что будет, если обратиться к словарю по ключу, которого в нем ещё нет?

Верно, исключение KeyError :

Не изобретать велосипед, или Обзор модуля collections в Python

После разговора о словарях самое время обсудить класс, умеющий объединять словари в надструктуру – ChainMap . При этом получается не один общий словарь, а их совокупность, в которой каждый словарь остаётся независимой составляющей:

Не изобретать велосипед, или Обзор модуля collections в Python

Объект типа deque (читается как «дэк», двусторонняя или двусвязная очередь) является усовершенствованным вариантом списка с оптимизированной вставкой/удалением элементов с обоих концов. Реализация deque оптимизирована так, что операции слева и справа имеют примерно одинаковую производительность O(1) . Добавление новых элементов в конец происходит не сильно медленнее, чем во встроенных списках, но добавление в начало выполняется существенно быстрее.

Не изобретать велосипед, или Обзор модуля collections в Python

namedtuple() – функция-фабрика для создания именованных кортежей. Этот тип данных похож на struct в других языках программирования:

>>> cols = ['fname', 'pname', 'lname', 'age'] >>> User = collections.namedtuple('User', cols) >>> user1 = User('Петр', 'Иванович', 'Сидоров', 30) >>> user1 User(fname='Петр', pname='Иванович', lname='Сидоров', age=30) >>> user1.lname Сидоров >>> Point = collections.namedtuple('Point', ['x', 'y']) >>> p = Point(3, 4) >>> p.x**2 + p.y**2 25 

Именованные кортежи делают код яснее – вместо индексирования составляющие объекта вызываются по явным именам. Остаётся доступной и численная индексация:

Именованные кортежи часто используются для назначения имён полей кортежам, возвращаемым модулями csv или sqlite3 :

EmployeeRecord = collections.namedtuple('EmployeeRecord', 'name, age, title, department, paygrade') import csv for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))): print(emp.name, emp.title) import sqlite3 conn = sqlite3.connect('/companydata') cursor = conn.cursor() cursor.execute('SELECT name, age, title, department, paygrade FROM employees') for emp in map(EmployeeRecord._make, cursor.fetchall()): print(emp.name, emp.title) 

Структура namedtuple похожа на словарь. Посредством метода _asdict можно представить те же данные в виде OrderedDict :

>>> p._asdict() OrderedDict([('x', 3), ('y', 4)]) 

Чтобы вызвать значение через строковый ключ, необязательно преобразовывать namedtuple – подходит стандартная функция getattr() :

Чтобы преобразовать словарь в именованный кортеж заданного типа, достаточно распаковать его оператором ** :

Имена полей namedtuple перечислены в _fields :

>>> user1._fields, p._fields (('fname', 'pname', 'lname', 'age'), ('x', 'y')) 

С версии 3.7 можно присвоить полям значения по умолчанию.

Поскольку именованный кортеж является обычным классом Python, в него легко привнести новую функциональность или изменить старую. Например, добавим к Point расчёт гипотенузы и формат вывода данных:

class Point(collections.namedtuple('Point', ['x', 'y'])): __slots__ = () # предотвращает создание словарей экземпляров @property def hypot(self): return (self.x**2 + self.y**2) ** 0.5 def __str__(self): return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot) for p in Point(3, 4), Point(14, 5/7): print(p) 
Point: x= 3.000 y= 4.000 hypot= 5.000 Point: x=14.000 y= 0.714 hypot=14.018 

Если вам пришлась по душе компактность namedtuple в сравнении с обычными классами и ваш проект может работать с версиями Python не меньше 3.7, присмотритесь к модулю dataclasses. Эта встроенная библиотека предоставляет декоратор и функции для автоматического добавления в пользовательские классы сгенерированных специальных методов, таких как __init__() и __repr__() .

Резюме

Подведём итог нашему рассказу об основных составляющих модуля collections:

  1. Counter – инструмент подсчёта неизменяемых объектов. Используйте, если нужно определить количество вхождений или число наиболее (наименее) часто встречающихся элементов.
  2. defaultdict – словарь, умеющий при вызове отсутствующего ключа вместо вызова исключения KeyError записывать значение по умолчанию (работает быстрее, чем метод setdefault() ).
  3. OrderedDict – словарь с памятью порядка добавления элементов, умеющий переупорядочивать элементы лучше, чем dict .
  4. ChainMap – контейнер комбинаций словарей с поиском, обобщением ключей и элементов.
  5. namedtuple() – функция-фабрика для создания именованного кортежа. Это один из простейших способов сделать код более ясным: использовать вместо индексов имена.
  6. deque – двусторонняя очередь – список, оптимизированный для вставки и удаления элементов с обоих концов с методом подсчёта вхождений
  7. UserDict, UserList, UserString – не заслуживающие развёрнутого описания обертки над стандартными объектами словарей, списков и строк для беспроблемного наследования (прямое наследование встроенным типам dict , list , str чревато ошибками, связанными с игнорированием переопределения методов).

Также у модуля collections имеется наследованный модуль коллекции абстрактных базовых классов сollections.abc . Но это тема отдельного разговора.

А вы уже используете collections в своих проектах?

Источник

Модуль collections на примерах

Модуль collections содержит специализированный контейнер типов данных, который может быть использован для замены контейнеров общего назначения Python (dict, tuple, list, и set). Мы изучим следующие части этого замечательного модуля:

Также существует наследованный модуль коллекций под названием abc, или Abstract Base Classes. Мы рассмотрим его в другой раз. Давайте начнем с контейнера ChainMap!

ChainMap

ChainMap – это класс, который дает возможность объединить несколько сопоставлений вместе таким образом, чтобы они стали единым целым. Если вы обратитесь к документации, то увидите, что данный класс принимает **maps*.

Это значит, что ChainMap будет принимать любое количество сопоставлений или словарей и превращать их в единое обновляемое представление. Давайте взглянем на пример, чтобы вы могли увидеть, как это работает:

Здесь мы импортировали ChainMap из модуля collections. Затем мы создали три словаря Python. Далее, мы создали экземпляр ChainMap, передав эти три словаря. В конце мы попытались получить доступ к одному из ключей в нашем ChainMap. После этого, ChainMap пройдет через каждое сопоставление, чтобы увидеть, существует ли данный ключ и имеет ли он значение. Если это так, тогда ChainMap вернет первое найденное значение, которое соответствует ключу. Это весьма полезно в тех случаях, когда вам нужно установить настройки по умолчанию.

Давайте представим, что нам нужно создать приложение, которое имеет определенные настройки по умолчанию. Приложение также будет знать о переменных среды операционной системы. Если существует переменная среды, которая соответствует значению ключа, который расположен в нашем приложении по умолчанию, тогда среда переопределит наши настройки по умолчанию. Теперь давайте представим, что мы можем передавать аргументы нашему приложению. Эти аргументы имеют преимущество над средой и настройками по умолчанию. Это тот случай, когда ChainMap представлен во всей красе. Давайте взглянем на пример, который основан на документации Python:

Давайте немного притормозим. Здесь мы импортировали модуль Python argparse совместно с модулем os. Мы также импортировали ChainMap.Next, простую функцию со слегка нелепыми настройками. Я видел, что эти настройки используются в некоторых популярных роутерах. Далее, мы устанавливаем наш парсер аргументов, и указываем ему, как именно он будет обрабатывать определенные параметры командной строки. Обратите внимание на то, что argparse не предоставляет способ получения объектов словаря или его аргументов, так что мы используем dict для извлечения того, что нам нужно. Здесь мы задействуем встроенный инструмент Python vars. Если вы вызовете его без аргументов, то vars будет вести себя как встроенный locals. Но если передать его объекту, то vars будет выступать в роли эквивалента свойству объекта __dict__. Другими словами, vars(args) равен args.__dict__. В конце мы создаем наш ChainMap, передав аргументы нашей командной строке (если таковые имеются), затем переменные среды и, наконец, настройки. В конце кода, мы пытаемся вызвать нашу функцию, затем устанавливаем переменные среды и снова делаем вызов. Запустите его и увидите, что в выдаче будет admin, и, как и ожидалось, test. Теперь попробуем вызвать скрипт с аргументом командной строки:

Источник

Читайте также:  Eclipse all in one python
Оцените статью