One place for hosting & domains

      Collections

      Cómo usar el módulo collections en Python 3


      El autor seleccionó el COVID-19 Relief Fund para que reciba una donación como parte del programa Write for DOnations.

      Introducción

      Python 3 tiene varias estructuras de datos integradas, incluyendo tuplas, diccionarios y listas. Las estructuras de datos nos proporcionan una forma de organizar y almacenar datos. El módulo collections nos ayuda a completar y manipular las estructuras de datos de forma eficiente.

      En este tutorial, veremos tres clases del módulo collections para ayudarle a trabajar con tuples, diccionarios y listas. Usaremos namedtuples para crear tuplas con campos con nombre, defaultdict para agrupar de forma concisa la información en diccionarios, y deque para añadir elementos de forma eficiente a cualquier lado de un objeto lista.

      Para este tutorial, trabajaremos principalmente con un inventario de peces que necesitamos modificar a medida que se añaden o retiran peces a un acuario ficticio.

      Requisitos previos

      Para sacar el máximo partido a este tutorial, se recomienda que esté algo familiarizado con los tipos de datos tupla, diccionario y lista, con su sintaxis y con cómo recuperar datos desde ellos. Puede revisar estos tutoriales para encontrar la información básica necesaria:

      Añadir campos con nombre a las tuplas

      Las tuplas de Python son secuencias de elementos ordenadas de forma inmutable o inalterable. Las tuplas se utilizan frecuentemente para representar datos en columnas; por ejemplo, líneas de un archivo CSV o filas de una base de datos SQL. Un acuario puede mantener un seguimiento de su inventario de peces como una serie de tuplas.

      Una tupla de peces individual:

      ("Sammy", "shark", "tank-a")
      

      Esta tupla está compuesta por tres elementos de cadena.

      Aunque es útil en cierta forma, esta tupla no indica claramente qué representa cada uno de sus campos. En realidad, el elemento 0 es un nombre, el elemento 1 es una especie y el elemento 2 es el depósito.

      Explicación de los campos de la tupla de peces:

      nombreespecietanque
      Sammytiburóntanque-a

      Esta tabla deja claro que cada uno de los tres elementos de la tupla tiene un significado claro.

      namedtuple del módulo collections le permite añadir nombres explícitos a cada elemento de una tupla para hacer que estos significados sean claros en su programa Python.

      Vamos a usar namedtuple para generar una clase que claramente denomine a cada elemento de la tupla de peces:

      from collections import namedtuple
      
      Fish = namedtuple("Fish", ["name", "species", "tank"])
      

      from collections import namedtuple proporciona a su programa Python acceso a la función de fábrica namedtuple. La invocación de la función namedtuple() devuelve una clase que está vinculada al nombre Fish. La función namedtuple() tiene dos argumentos: el nombre deseado de nuestra nueva clase "Fish" y una lista de elementos denominados ["name", "species", "tank"].

      Podemos usar la clase Fish para representar la tupla de peces anterior:

      sammy = Fish("Sammy", "shark", "tank-a")
      
      print(sammy)
      

      Si ejecuta este código, verá el siguiente resultado:

      Output

      Fish(name="Sammy", species="shark", tank='tank-a')

      sammy se instancia usando la clase Fish. sammy es una tupla con tres elementos claramente nombrados.

      Se puede acceder a los campos de sammy por su nombre o con un índice de tupla tradicional:

      print(sammy.species)
      print(sammy[1])
      

      Si ejecutamos estas dos invocaciones print, veremos el siguiente resultado:

      Output

      shark shark

      Acceder a .species devuelve el mismo valor que acceder al segundo elemento de sammy usando [1]​​​.

      Usar namedtuple desde el módulo collections hace que su programa sea más legible al tiempo que mantiene las propiedades importantes de una tupla (que son inmutables y están ordenadas).

      Además, la función de fábrica namedtuple añade varios métodos adicionales para las instancias de Fish.

      Utilice ._asdict() para convertir una instancia en un diccionario:

      print(sammy._asdict())
      

      Si ejecutamos print, verá un resultado como el siguiente:

      Output

      {'name': 'Sammy', 'species': 'shark', 'tank': 'tank-a'}

      Invocar .asdict() en sammy devuelve una asignación de diccionario de cada uno de los tres nombres de campo con sus correspondientes valores.

      Las versiones de Python anteriores a 3.8 pueden mostrar esta línea de forma ligeramente diferente. Es posible, por ejemplo, que vea OrderedDict en vez del diccionario simple mostrado aquí.

      Nota: En Python, los métodos con guiones bajos precedentes se consideran, normalmente, “privados”. Los métodos adicionales proporcionados por namedtuple (por ejemplo, _asdict(), ._make(), ._replace(), etc.), sin embargo, son públicos.

      Recoger datos en un diccionario

      A menudo es útil recopilar datos en los diccionarios Python. defaultdict del módulo collections puede ayudarnos a ensamblar información en diccionarios de forma rápida y concisa.

      defaultdict nunca plantea un KeyError. Si no está presente una clave, defaultdict solo inserta y devuelve un valor de marcador de posición:

      from collections import defaultdict
      
      my_defaultdict = defaultdict(list)
      
      print(my_defaultdict["missing"])
      

      Si ejecutamos este código, veremos un resultado como el siguiente:

      Output

      []

      defaultdict inserta y devuelve un valor de marcador de posición en vez de lanzar un KeyError. En este caso, especificamos el valor de marcador de posición como una lista.

      Los diccionarios regulares, por el contrario, lanzarán un KeyError sobre las claves que faltan:

      my_regular_dict = {}
      
      my_regular_dict["missing"]
      

      Si ejecutamos este código, veremos un resultado como el siguiente:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'missing'

      El diccionario regular my_regular_dict plantea un KeyError cuando intentamos acceder a una clave que no está presente.

      defaultdict se comporta de forma diferente a un diccionario regular. En vez de plantear un KeyError sobre una clave que falta, defaultdict invoca el valor de marcador de posición sin argumentos para crear un nuevo objeto. En este caso list() para crear una lista vacía.

      Continuando con nuestro ejemplo de acuario ficticio, digamos que tenemos una lista de tuplas de peces que representan el inventario de un acuario:

      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      

      Existen tres peces en el acuario; sus nombres, especies y tanque se anotan en estas tres tuplas.

      Nuestro objetivo es organizar nuestro inventario por tanque; queremos conocer la lista de peces presentes en cada tanque. En otras palabras, queremos un diccionario que asigne "tank-a" a ["Jamie", "Mary"] y "tank-b" a ["Jamie"].

      Podemos usar defaultdict para agrupar los peces por tanque:

      from collections import defaultdict
      
      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      fish_names_by_tank = defaultdict(list)
      for name, species, tank in fish_inventory:
          fish_names_by_tank[tank].append(name)
      
      print(fish_names_by_tank)
      

      Cuando ejecutemos este código, veremos el siguiente resultado:

      Output

      defaultdict(<class 'list'>, {'tank-a': ['Sammy', 'Mary'], 'tank-b': ['Jamie']})

      fish_names_by_tank se declara como un defaultdict que va por defecto a insertar list() en vez de lanzar un KeyError. Ya que esto garantiza que cada clave en fish_names_by_tank apuntará a una lista, podemos invocar libremente .append() para añadir nombres a la lista de cada tanque.

      defaultdict le ayuda aquí porque reduce la probabilidad de KeyErrors inesperados. Reducir los KeyErrors inesperados significa que su programa puede escribirse de forma más clara y con menos líneas. Más concretamente, el idioma defaultdict le permite evitar instanciar manualmente una lista vacía para cada tanque.

      Sin defaultdict, el cuerpo de bucle for podría haber tenido un aspecto más similar a este:

      More Verbose Example Without defaultdict

      ...
      
      fish_names_by_tank = {}
      for name, species, tank in fish_inventory:
          if tank not in fish_names_by_tank:
            fish_names_by_tank[tank] = []
          fish_names_by_tank[tank].append(name)
      

      Usar simplemente un diccionario regular (en vez de un defaultdict) significa que el cuerpo de bucle for siempre tiene que comprobar la existencia de tank dado en fish_names_by_tank. Solo tras haber verificado que tank ya está presente en fish_names_by_tank, o que ha sido inicializado con un [], podremos anexar el nombre del pez.

      defaultdict puede ayudar a reducir el código de plantilla cuando se completan diccionarios, porque nunca plantea un KeyError.

      Usar deque para añadir elementos de forma eficiente a cada lado de una colección

      Las listas de Python son secuencias de elementos ordenadas mutables, o alterables. Python puede anexar a listas en tiempo constante (la longitud de la lista no tiene efecto sobre el tiempo en que se tarda en anexar), pero insertar al principio de una lista puede ser más lento (el tiempo que tarda aumenta a medida que la lista aumenta).

      En términos de la notación Big O, anexar a una lista es una operación O(1) de tiempo constante. Insertar al principio de una lista, por el contrario, es más lento con el rendimiento de O(n).

      Nota: Los ingenieros de software a menudo miden el rendimiento de los procedimientos usando algo llamado la notación “Big O”. Cuando el tamaño de una entrada no tiene efecto sobre el tiempo que se tarda en realizar un procedimiento, se dice que se ejecuta en tiempo constante u O(1) (“Big O de 1”) Como ha aprendido antes, Python puede anexar a listas con un rendimiento de tiempo constante, conocido como O(1).

      A veces, el tamaño de una entrada afecta directamente a la cantidad de tiempo que se tarda en ejecutar un procedimiento. Insertar al principio de una lista Python, por ejemplo, es más lento cuantos más elementos haya en la lista. La notación Big O utiliza la letra n para representar el tamaño de la entrada. Esto significa que añadir elementos al principio de una lista Python se ejecuta en “tiempo lineal” u O(n) (“Big O de n”).

      En general, los procedimientos O(1) son más rápidos que los procedimientos O(n).

      Podemos insertar al principio de una lista Python:

      favorite_fish_list = ["Sammy", "Jamie", "Mary"]
      
      # O(n) performance
      favorite_fish_list.insert(0, "Alice")
      
      print(favorite_fish_list)
      

      Si ejecutamos lo siguiente, veremos un resultado como el siguiente:

      Output

      ['Alice', 'Sammy', 'Jamie', 'Mary']

      El método .insert(index, object) en la lista nos permite insertar "Alice" al principio de favorite_fish_list. Notablemente, sin embargo, insertar al principio de una lista tiene un rendimiento O(n). A medida que la longitud de favorite_fish_list aumenta, el tiempo para insertar un pez al principio de la lista aumentará proporcionalmente y tardará cada vez más.

      deque (pronunciado “deck”) del módulo collections es un objeto tipo listado que nos permite insertar elementos al principio o al final de una secuencia con un rendimiento de tiempo constante O(1).

      Insertar un elemento al principio de un deque:

      from collections import deque
      
      favorite_fish_deque = deque(["Sammy", "Jamie", "Mary"])
      
      # O(1) performance
      favorite_fish_deque.appendleft("Alice")
      
      print(favorite_fish_deque)
      

      Al ejecutar este código, veremos el siguiente resultado:

      Output

      deque(['Alice', 'Sammy', 'Jamie', 'Mary'])

      Podemos instanciar un deque usando una colección de elementos preexistente, en este caso una lista de nombres de tres peces favoritos. Invocar el método appendleft de favorite_fish_deque nos permite insertar un elemento al principio de nuestra colección con un rendimiento O(1). El rendimiento O(1) significa que el tiempo que se requiere para añadir un elemento al principio de favorite_fish_deque no aumentará incluso si favorite_fish_deque tiene miles o millones de elementos.

      Nota: Aunque deque añade entradas al principio de una secuencia de forma más eficiente que una lista, deque no realiza todas sus operaciones de forma más eficiente que una lista. Por ejemplo, acceder a un elemento aleatorio en un deque tiene un rendimiento O(n), pero acceder a un elemento aleatorio en una lista tiene un rendimiento O(1). Utilice deque cuando sea importante insertar o eliminar elementos de cualquier lado de su colección rápidamente. Podrá ver una comparativa completa del rendimiento de tiempo en la wiki de Python.

      Conclusión

      El módulo collections es una parte potente de la biblioteca estándar de Python que le permite trabajar con datos de forma concisa y eficiente. Este tutorial ha cubierto tres de las clases proporcionadas por el módulo collections incluyendo namedtuple, defaultdict y deque.

      Desde aquí, puede usar la documentación del módulo collectionpara aprender más sobre otras clases y utilidades disponibles. Para obtener más información sobre Python en general, puede leer nuestra serie de tutoriales Cómo codificar en Python 3.



      Source link

      Использование модуля collections в Python 3


      Автор выбрал COVID-19 Relief Fund для получения пожертвования в рамках программы Write for DOnations.

      Введение

      В Python 3 имеется множество встроенных структур данных, включая кортежи, словари и списки. Структуры данных дают нам возможности организации и хранения данных. Модуль collections помогает эффективно заполнять структуры данных и управлять ими.

      В этом обучающем модуле мы рассмотрим три класса модуля collections, которые помогут вам работать с кортежами, словарями и списками. Мы используем namedtuples для создания кортежей с именованными полями, defaultdict для удобного группирования информации в словарях и деки для эффективного добавления элементов на любую сторону объекта в виде списка.

      В этом обучающем модуле мы будем работать со списком рыб, изменяемым по мере добавления или удаления рыб из вымышленного аквариума.

      Предварительные требования

      Чтобы использовать этот обучающий модуль с наибольшей эффективностью, мы рекомендуем познакомиться с типами данных «кортеж», «словарь» и «список», их синтаксисом и способами извлечения данных из этих типов. Необходимую информацию можно получить, пройдя следующие обучающие модули:

      Добавление именованных полей в кортежи

      Кортежи Python представляют собой неизменяемые упорядоченные последовательности элементов. Кортежи часто используются для представления табличных данных, например, строк из файла CSV или базы данных SQL. Аквариум может отслеживать список рыбок как серию кортежей.

      Кортеж отдельной рыбки:

      ("Sammy", "shark", "tank-a")
      

      Этот кортеж состоит из трех строковых элементов.

      Хотя это полезно, данный массив четко не показывает, что означает каждое из полей. На самом деле элемент 0 — это имя, элемент 1 — это вид, а элемент 2 — резервуар.

      Значение полей кортежа fish:

      namespeciestank
      Sammysharktank-a

      В этой таблице понятно, что каждый из трех элементов кортежа имеет четкое значение.

      namedtuple из модуля collections позволяет добавлять явные имена в каждый элемент кортежа, чтобы сделать их значения понятными в вашей программе Python.

      Давайте используем namedtuple для генерирования класса, который дает четкие имена каждому элементу кортежа fish:

      from collections import namedtuple
      
      Fish = namedtuple("Fish", ["name", "species", "tank"])
      

      from collections import namedtuple дает вашей программе Python доступ к функции фабрики namedtuple. Вызов функции namedtuple() возвращает класс, привязанный к имени Fish. Функция namedtuple() имеет два аргумента: желаемое имя нового класса "Fish" и список именованных элементов ["name", "species", "tank"].

      Мы можем использовать класс Fish для представления описанного выше кортежа fish:

      sammy = Fish("Sammy", "shark", "tank-a")
      
      print(sammy)
      

      Если мы выполним этот код, мы увидим следующие результаты:

      Output

      Fish(name="Sammy", species="shark", tank='tank-a')

      Создается экземпляр sammy с использованием класса Fish. sammy — это кортеж из трех элементов с понятными именами.

      Доступ к полям sammy осуществляется по имени или через традиционный индекс кортежа:

      print(sammy.species)
      print(sammy[1])
      

      Если мы выполним эти два вызова print, результат будет выглядеть так:

      Output

      shark shark

      При доступе к.species возвращается то же значение, что и при доступе ко второму элементу sammy с использованием [1].

      Использование namedtuple из модуля collections делает программу более удобочитаемой и при этом позволяет сохранить важные свойства кортежа (неизменяемость и упорядоченность).

      Кроме того, функция фабрики namedtuple добавляет несколько дополнительных методов в экземпляры Fish.

      Используйте ._asdict() для конвертации экземпляра в словарь:

      print(sammy._asdict())
      

      Если мы выполним команду print, результат будет выглядеть так:

      Output

      {'name': 'Sammy', 'species': 'shark', 'tank': 'tank-a'}

      При вызове .asdict() для пользователя sammy будет выведена схема словаря, где каждое из трех имен полей будет сопоставлено с соответствующим значением.

      В версиях Python ниже 3.8 эта строка может выводиться немного по-другому. Например, вместо показанного здесь простого словаря вы можете увидеть OrderedDict.

      Примечание. В Python методы, начинающиеся с символа подчеркивания, обычно считаются «частными». При этом дополнительные методы, предоставляемые namedtuple (_asdict(), ._make(), ._replace() и т. д.) являются публичными.

      Сбор данных в словаре

      Часто бывает полезно собирать данные в словарях Python. Словарь defaultdict из модуля collections может помочь быстро и кратко собрать информацию в словарях.

      defaultdict никогда не генерирует ошибку KeyError. При отсутствии ключа defaultdict просто вставляет и возвращает подстановочное значение:

      from collections import defaultdict
      
      my_defaultdict = defaultdict(list)
      
      print(my_defaultdict["missing"])
      

      Если запустить этот код, результат будет выглядеть следующим образом:

      Output

      []

      defaultdict вставляет и возвращает подстановочное значение вместо генерирования ошибки KeyError. В этом случае мы задали подстановочное значение как список.

      Обычные словари в подобных случаях выдают ошибку KeyError при отсутствии ключей:

      my_regular_dict = {}
      
      my_regular_dict["missing"]
      

      Если запустить этот код, результат будет выглядеть следующим образом:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'missing'

      Обычный словарь my_regular_dict генерирует ошибку KeyError при попытке доступа к отсутствующему ключу.

      Поведение defaultdict отличается от поведения обычного словаря. Вместо генерирования ошибки KeyError при отсутствии ключа defaultdict вызывает подстановочное значение без аргументов для создания нового объекта. В данном случае это list() для создания пустого списка.

      Продолжим рассмотрение нашего примера вымышленного аквариума. Допустим, у нас имеется список кортежей fish, представляющий содержимое аквариума:

      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      

      В аквариуме три рыбки, и их названия, виды и резервуары указываются в этих трех кортежах.

      Наша цель — организовать инвентарный список по резервуарам и получить список рыб, присутствующих в каждом резервуаре. Другими словами, нам нужен словарь, сопоставляющий "tank-a" с ["Jamie", "Mary"] и "tank-b" с ["Jamie"].

      Мы можем использовать defaultdict для группировки рыб по резервуарам:

      from collections import defaultdict
      
      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      fish_names_by_tank = defaultdict(list)
      for name, species, tank in fish_inventory:
          fish_names_by_tank[tank].append(name)
      
      print(fish_names_by_tank)
      

      Запустив этот код, мы получим следующий результат:

      Output

      defaultdict(<class 'list'>, {'tank-a': ['Sammy', 'Mary'], 'tank-b': ['Jamie']})

      fish_names_by_tank декларируется как словарь defaultdict, который по умолчанию вставляет list() вместо вывода ошибки KeyError. Поскольку при этом каждый ключ в fish_names_by_tank будет гарантированно указывать на список, мы можем свободно вызывать .append() для добавления имен в списки каждого резервуара.

      В данном случае defaultdict будет полезен, поскольку он сокращает вероятность непредвиденных ошибок KeyError. Сокращение числа непредвиденных ошибок KeyError означает, что программа будет содержать меньше строк и будет более понятной. В частности, идиома defaultdict позволяет избежать создания экземпляров пустых списков для каждого резервуара вручную.

      Без defaultdict цикл for выглядел бы примерно так:

      More Verbose Example Without defaultdict

      ...
      
      fish_names_by_tank = {}
      for name, species, tank in fish_inventory:
          if tank not in fish_names_by_tank:
            fish_names_by_tank[tank] = []
          fish_names_by_tank[tank].append(name)
      

      Если используется обычный словарь (вместо defaultdict), цикл for всегда должен проверять наличие определенного резервуара в fish_names_by_tank. Имя рыбки можно добавить только после подтверждения наличия резервуара в fish_names_by_tank или его инициализации с помощью [].

      defaultdict помогает сократить объем кода при заполнении словарей, поскольку никогда не генерирует ошибки KeyError.

      Использование дек для эффективного добавления элементов с любой стороны набора

      Списки Python представляют собой изменяемые упорядоченные последовательности элементов. Python может добавлять элементы в списки за постоянное время (длина списка не влияет на время добавления), однако вставка в начало списка выполняется медленнее, и время такой вставки увеличивается с ростом размера списка.

      С точки зрения нотации Big O добавление в список представляет собой операцию O(1) с постоянным временем. Вставка в начало списка выполняется медленнее, с производительностью O(n).

      Примечание. Инженеры-разработчики часто измеряют производительность процедур с помощью нотации «Big O». Если размер ввода не влияет на время выполнения процедуры, считается, что она выполняется за постоянное время или O(1) (“Big O of 1”). Как уже говорилось выше, Python может добавлять элементы в списки за постоянное время или O(1).

      Иногда размер ввода напрямую влияет на время выполнения процедуры. Например, вставка в начало списка Python выполняется тем медленнее, чем больше элементов содержится в списке. В нотации Big O для определения размера ввода используется буква n. Это означает, что для добавления элементов в начало списка Python требуется «линейное время» или O(n) (“Big O of n”).

      В целом процедуры O(1) быстрее процедур O(n).

      Мы можем выполнить вставку в начало списка Python:

      favorite_fish_list = ["Sammy", "Jamie", "Mary"]
      
      # O(n) performance
      favorite_fish_list.insert(0, "Alice")
      
      print(favorite_fish_list)
      

      Если мы выполним следующий код, результат будет выглядеть так:

      Output

      ['Alice', 'Sammy', 'Jamie', 'Mary']

      Метод .insert(index, object) в списке позволяет нам вставить "Alice" в начало списка favorite_fish_list. Следует отметить, что вставка в начало списка осуществляется с производительностью O(n). По мере увеличения длины списка favorite_fish_list увеличивается и время вставки имени рыбки в начало списка.

      дека (двусторонняя очередь) из модуля collections — это объект списка, позволяющий вставлять элементы в начало или конец последовательности за постоянное время (O(1)).

      Вставьте элемент в начало деки:

      from collections import deque
      
      favorite_fish_deque = deque(["Sammy", "Jamie", "Mary"])
      
      # O(1) performance
      favorite_fish_deque.appendleft("Alice")
      
      print(favorite_fish_deque)
      

      Выполнив этот код, мы получим следующий результат:

      Output

      deque(['Alice', 'Sammy', 'Jamie', 'Mary'])

      Мы можем создать экземпляр деки, используя готовый набор элементов. В данном случае это список из трех имен любимых рыбок. Вызов метода favorite_fish_deque appendleft позволяет нам вставить элемент в начало набора с производительностью O(1). Производительность O(1) означает, что время добавления элемента в начало favorite_fish_deque не увеличивается, даже если favorite_fish_deque содержит тысячи или миллионы элементов.

      Примечание. Хотя дека позволяет добавлять записи в начало последовательности более эффективно, чем список, дека не выполняет все операции более эффективно, чем список. Например, доступ к случайному элементу деки осуществляется с производительностью O(n), а доступ к случайному элементу списка — с производительностью O(1). Деки используются, когда нам важно быстро вставлять и удалять элементы с любой стороны набора. Полное сравнение производительности по времени можно найти в вики-справочнике по Python.

      Заключение

      Модуль collections — мощный элемент стандартной библиотеки Python, делающий работу с данными более краткой и эффективной. В этом обучающем модуле мы рассказали о трех классах модуля collections: namedtuple, defaultdict и deque.

      Теперь вы можете использовать документацию по модулю collection, чтобы узнать больше о других доступных классах и утилитах. Чтобы узнать больше о Python в целом, пройдите нашу серию обучающих модулей «Программирование на Python 3».



      Source link

      Comment utiliser le module des collections dans Python 3


      L’auteur a choisi le COVID-19 Relief Fund pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      Python 3 possède un certain nombre de structures de données intégrées, notamment des tuples, des dictionnaires et des listes. Les structures de données nous fournissent un moyen d’organiser et de stocker les données. Le module de collections nous aide à remplir et à manipuler les structures de données de manière efficace.

      Dans ce tutoriel, nous allons passer en revue trois classes des collections pour vous aider à travailler avec des tuples, des dictionnaires et des listes. Nous utiliserons namedtuples pour créer des tuples avec des champs nommés, defaultdict pour regrouper de manière concise les informations dans les dictionnaires, et deque pour ajouter efficacement des éléments de chaque côté d’un objet de type liste. 

      Pour ce tutoriel, nous travaillerons principalement avec un inventaire de poissons que nous devons modifier au fur et à mesure que des poissons sont ajoutés ou retirés d’un aquarium fictif.

      Conditions préalables

      Pour tirer le meilleur parti de ce tutoriel, il est recommandé de se familiariser avec le tuple, le dictionnaire et les types de données de liste que ce soit en ce qui concerne leur syntaxe que de la manière d’en extraire des données. Vous pouvez consulter ces tutoriels pour obtenir les informations de base nécessaires :

      Ajouter des champs nominatifs aux tuples

      Les tuples de Python sont une séquence d’éléments immuables, ou inchangeables, ordonnés. Les tuples sont fréquemment utilisés pour représenter des données en colonnes ; par exemple, les lignes d’un fichier CSV ou les lignes d’une base de données SQL. Un aquarium peut garder une trace de son inventaire de poissons sous la forme d’une série de tuples.

      Un tuple de poissons individuel :

      ("Sammy", "shark", "tank-a")
      

      Ce tuple est composé de trois éléments de chaîne caractères.

      Bien qu’utile à certains égards, ce tuple n’indique pas clairement ce que représente chacun de ses champs. En réalité, l’élément 0 est un nom, l’élément 1 est une espèce, et l’élément 2 est le réservoir de stockage. 

      Explication des champs de tuples de poissons :

      namespeciestank
      Sammysharktank-a

      Ce tableau montre clairement que chacun des trois éléments du tuple a une signification claire.

      namedtuple du module collections vous permet d’ajouter des noms explicites à chaque élément d’un tuple pour rendre ces significations claires dans votre programme Python.

      Utilisons namedtuple pour générer une classe qui nomme clairement chaque élément du tuple de poisson :

      from collections import namedtuple
      
      Fish = namedtuple("Fish", ["name", "species", "tank"])
      

      from collections import namedtuple donne à votre programme Python l’accès à la fonction d’usine namedtuple. L’appel de la fonction namedtuple() renvoie une classe qui est liée au nom Fish. Le namedtuple() a deux arguments : le nom souhaité de notre nouvelle classe "Fish" et une liste d’éléments nommés ["name", "species", "tank"]. 

      Nous pouvons utiliser la classe Fish pour représenter le tuple de poissons de tout à l’heure :

      sammy = Fish("Sammy", "shark", "tank-a")
      
      print(sammy)
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      Output

      Fish(name="Sammy", species="shark", tank='tank-a')

      sammy est instancié à l’aide de la classeFish. sammy est un tuple avec trois éléments clairement nommés. 

      Les champs de sammy sont accessibles par leur nom ou avec un index tuple traditionnel :

      print(sammy.species)
      print(sammy[1])
      

      Si nous lançons ces deux appels d’impression, nous obtiendrons le résultat suivant :

      Output

      shark shark

      L’accès à .species a la même valeur que l’accès au deuxième élément de sammy en utilisant [1]. 

      Utiliser namedtuple du module collections rend votre programme plus lisible tout en conservant les propriétés importantes d’un tuple (à savoir qu’ils sont immuables et ordonnés). 

      De plus, la fonction d’usine namedtuple ajoute plusieurs méthodes supplémentaires aux instances de Fish.

      Utilisez ._asdict() pour convertir une instance en dictionnaire :

      print(sammy._asdict())
      

      Si nous lançons print, vous verrez des résultats comme ceux qui suivent :

      Output

      {'name': 'Sammy', 'species': 'shark', 'tank': 'tank-a'}

      Appeler .asdict() sur sammy renvoie un dictionnaire mettant en correspondance les noms de chacun des trois champs avec leurs valeurs correspondantes. 

      Les versions de Python plus anciennes que 3.8 pourraient produire cette ligne de manière légèrement différente. Vous pourriez, par exemple, voir un OrderedDict au lieu du simple dictionnaire présenté ici. 

      Note : Dans Python, les méthodes avec des traits de soulignement en tête sont généralement considérées comme « privées ». Les méthodes supplémentaires fournies par namedtuple (comme _asdict(), ._make(), ._replace(), etc.), sont toutefois publiques.

      Rassembler des données dans un dictionnaire

      Il est souvent utile de collecter des données dans les dictionnaires Python. defaulttdict du module de collections peut nous aider à rassembler les informations dans les dictionnaires de manière rapide et concise. 

      defaultdict ne soulève jamais une KeyError. Si une clé n’est pas présente, defaulttdict se contente d’insérer et de renvoyer une valeur de remplacement à la place : 

      from collections import defaultdict
      
      my_defaultdict = defaultdict(list)
      
      print(my_defaultdict["missing"])
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      Output

      []

      defaultdict insère et renvoie une valeur de remplacement au lieu de lancer une KeyError. Dans ce cas, nous avons spécifié la valeur de remplacement sous forme de liste.

      Les dictionnaires ordinaires, en revanche, lancent une KeyError sur les clés manquantes :

      my_regular_dict = {}
      
      my_regular_dict["missing"]
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'missing'

      Le dictionnaire habituel my_regular_dict soulève une KeyError lorsque nous essayons d’accéder à une clé qui n’est pas présente. 

      defaulttdict se comporte différemment d’un dictionnaire ordinaire. Au lieu de soulever une KeyError sur une clé manquante, defaultdict appelle la valeur de remplacement sans argument pour créer un nouvel objet. Dans ce cas, list() pour créer une liste vide. 

      Pour continuer avec notre exemple d’aquarium fictif, disons que nous avons une liste de tuples de poissons représentant l’inventaire d’un aquarium :

      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      

      Trois poissons existent dans l’aquarium – leur nom, leur espèce et leur bac de rétention sont notés dans ces trois tuples.

      Notre objectif est d’organiser notre inventaire par réservoir – nous voulons connaître la liste des poissons présents dans chaque réservoir. En d’autres termes, nous voulons un dictionnaire qui cartographie "tank-a". à ["Jamie", "Mary"] et "tank-b" à ["Jamie"].

      Nous pouvons utiliser defaulttdict pour regrouper les poissons par bassin :

      from collections import defaultdict
      
      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      fish_names_by_tank = defaultdict(list)
      for name, species, tank in fish_inventory:
          fish_names_by_tank[tank].append(name)
      
      print(fish_names_by_tank)
      

      En exécutant ce code, nous obtiendrons le résultat suivant :

      Output

      defaultdict(<class 'list'>, {'tank-a': ['Sammy', 'Mary'], 'tank-b': ['Jamie']})

      fish_names_by_tank est déclaré comme un paramètre par défaut qui consiste par défaut à insérer list() au lieu de lancer une KeyError.  Comme cela garantit que chaque clé dansfish_names_by_tank pointera sur une liste, nous pouvons librement appeler .append() pour ajouter des noms à la liste de chaque réservoir.

      defaultdict vous aide ici car il réduit le risque d’erreurs inattendues de KeyErrors. Réduire lesKeyErrors inattendues signifie que votre programme peut être écrit plus clairement et avec moins de lignes. Plus concrètement, l’idiome defaultdict permet d’éviter d’instancier manuellement une liste vide pour chaque réservoir.

      Sans défaultdict, le corps de la boucle for aurait pu ressembler davantage à ceci :

      More Verbose Example Without defaultdict

      ...
      
      fish_names_by_tank = {}
      for name, species, tank in fish_inventory:
          if tank not in fish_names_by_tank:
            fish_names_by_tank[tank] = []
          fish_names_by_tank[tank].append(name)
      

      L’utilisation d’un simple dictionnaire (au lieu d’un defaultdict) signifie que le corps de la boucle for doit toujours vérifier l’existence du tank donné dans fish_names_by_tank. Ce n’est qu’après avoir vérifié que tank est déjà présent dans fish_names_by_tank, ou vient d’être initialisé avec un [], qu’on peut ajouter le nom du poisson.

      defaultdict peut aider à réduire le nombre de codes passe-partout lors du remplissage des dictionnaires car il ne provoque jamais de KeyError.

      Utilisation de deque pour ajouter efficacement des éléments de chaque côté d’une collection

      Les listes Python sont une séquence d’éléments ordonnée, mutable ou modifiable. Python peut ajouter des listes en temps constant (la longueur de la liste n’a aucun effet sur le temps qu’il faut pour l’ajout), mais l’insertion au début d’une liste peut être plus lente (le temps nécessaire augmente à mesure que la liste s’agrandit).

      En termes de notation Big O, l’ajout à une liste est une opération O(1) à temps constant. L’insertion au début d’une liste, en revanche, est plus lente avec O(n) performance. 

      Note : Les informaticiens mesurent souvent la performance des procédures en utilisant ce qu’on appelle la notation « Big O ». Lorsque la taille d’une entrée n’a aucun effet sur le temps nécessaire pour exécuter une procédure, on dit qu’elle se déroule en temps constant ou O(1) (“Big O of 1”). Comme vous l’avez appris plus haut, Python peut s’ajouter aux listes à performance temporelle constante, autrement dit O(1). 

      Parfois, la taille d’une entrée a une incidence directe sur le temps nécessaire à l’exécution d’une procédure. L’insertion au début d’une liste Python, par exemple, est d’autant plus lente qu’il y a plus d’éléments dans la liste. La notation Big O utilise la lettre n pour représenter la taille de l’entrée. Cela signifie que l’ajout d’éléments au début d’une liste Python se fait en « temps linéaire » ou O(n) (“Big O of n”). 

      En général, les procédures O(1) sont plus rapides que les procédures O(n).

      On peut l’insérer au début d’une liste Python :

      favorite_fish_list = ["Sammy", "Jamie", "Mary"]
      
      # O(n) performance
      favorite_fish_list.insert(0, "Alice")
      
      print(favorite_fish_list)
      

      Si nous exécutons ce qui suit, nous obtiendrons le résultat suivant :

      Output

      ['Alice', 'Sammy', 'Jamie', 'Mary']

      La méthode .insert (index, objet) sur list nous permet d’insérer "Alice" au début de favorite_fish_list. Toutefois, il est à noter que l’insertion au début d’une liste a O(n) performance. Comme la durée de favorite_fish_list augmente, le temps nécessaire pour insérer un poisson au début de la liste augmentera proportionnellement et prendra de plus en plus de temps.

      deque (prononcé « deck ») du module collections est un objet de type liste qui nous permet d’insérer des éléments au début ou à la fin d’une séquence avec une performance à temps constant (O(1)).

      Insérez un élément au début d’un deque: 

      from collections import deque
      
      favorite_fish_deque = deque(["Sammy", "Jamie", "Mary"])
      
      # O(1) performance
      favorite_fish_deque.appendleft("Alice")
      
      print(favorite_fish_deque)
      

      En exécutant ce code, nous obtiendrons le résultat suivant :

      Output

      deque(['Alice', 'Sammy', 'Jamie', 'Mary'])

      Nous pouvons instancier un deque en utilisant un ensemble d’éléments préexistants, en l’occurrence une liste de trois noms de poissons favoris. L’appel de la méthode appendleft de favorite_fish_deque nous permet d’insérer un élément au début de notre collection avec la performance O (1). O(1) performance signifie que le temps nécessaire pour ajouter un élément au début de favorite_fish_deque n’augmentera pas, même si favorite_fish_deque a des milliers ou des millions d’éléments. 

      Note : Bien que deque ajoute des entrées au début d’une séquence plus efficacement qu’une liste, deque n’effectue pas toutes ses opérations plus efficacement qu’une liste. Par exemple, l’accès à un article aléatoire dans un deque a une performance O(n), mais l’accès à un élément aléatoire d’une liste a une performance O(1). Utilisez deque lorsqu’il est important d’insérer ou de retirer rapidement des éléments de chaque côté de votre collection. Une comparaison complète des performances temporelles est disponible sur le wiki de Python.

      Conclusion

      Le module des collections est une partie puissante de la bibliothèque standard Python qui vous permet de travailler avec des données de manière concise et efficace.  Ce tutoriel couvrait trois des cours fournis par le module des collections comprenant namedtuple, defaultdict, et deque. 

      D’ici, vous pouvez utiliser la documentation du module de collecte pour en savoir plus sur les autres classes et utilités disponibles. Pour en savoir plus sur Python en général, vous pouvez lire notre Série de tutoriels Comment coder en Python 3. 



      Source link