В чем разница между перечислением и namedtuple?
Я хотел бы знать, в чем разница между перечислением и namedtuple и когда следует использовать одно над другим.
2 ответа:
В качестве аналогии (хотя и несовершенной), вы можете думать о
Я думаю, что этот пример иллюстрирует разницу.enum.Enum
иnamedtuple
в python как оenum
иstruct
В C. другими словами,enum
s-это способ сглаживания значений, аnamedtuple
- способ инкапсуляции данных по имени. Эти два типа не являются взаимозаменяемыми, и вы можете использоватьenum
s в качестве именованных значений вnamedtuple
.from collections import namedtuple from enum import Enum class HairColor(Enum): blonde = 1 brown = 2 black = 3 red = 4 Person = namedtuple('Person', ['name','age','hair_color']) bert = Person('Bert', 5, HairColor.black)
Вы можете получить доступ к именованным "атрибутам" человека так же, как и к обычным объект.
>>> print(bert.name) Bert >>> print(bert.age) 5 >>> print(bert.hair_color) HairColor.black >>> print(bert.hair_color.value) 3
Вы часто не видите
namedtuple
так, потому что та же самая существенная концепция может быть реализована с помощью более широко известного объявленияclass
. Определениеclass
ниже ведет себя почти так же, как определениеnamedtuple
выше.Однако основное различие между объектомclass Person: def __init__(self, name, age, hair_color): self.name = name self.age = age self.hair_color = hair_color
namedtuple
и объектомclass
состоит в том, что атрибуты объектаnamedtuple
не могут быть изменены после его создания.
Namedtuple - это быстрая структура, которая, используя __slots__ вместо __dict__, завершает содержимое, которое вы предоставляете при инициализации (что практически становится доступным только для чтения, хотя метод _replace() существует).
Namedtuple обычно используется, когда вам нужно много (например, сотни, тысячи и даже миллионы) объектов одного типа или Вы читаете и/или записываете запись.
Например, часто приводимый пример-это точка namedtuple, который может использоваться для работы с вершиной полигона с ее компонентамиx, y, z
.
накладные расходы, вносимые namedtuple над регулярным кортежем, минимальны по сравнению с преимуществом всегда указывать на правильный компонент по имени (.икс, .год, .Зет, ...) вместо по индексу (0, 1, 2, ...).
Чтение кода, такого как A. x, проще, чем A[0]: смысл очевиден даже через несколько месяцев после написания кода и, что еще лучше, для других программистов.Таким образом, a namedtuple быстр, может использоваться для значимой идентификации содержимого кортежа и, наконец, может сосуществовать с более старым кодом, получающим доступ к содержимому кортежа по индексу.
from collections import namedtuple Point = namedtuple('Point', 'x y z') # note the x, y, z fields origin = Point(0, 0, 0) A = Point(1, 1, 1) B = Point(1, 1, 0) C = Point(1, 0, 0) D = Point(1, 2, 3) for p in (origin, A, B, C, D): print(p) print('x:', p.x, ' y:', p.y, ' z:', p.z) print('x:', p[0], ' y:', p[1], ' z:', p[2]) print()
Исходя из приведенного выше примера, как только все обращается к компонентам точек по имени, а не по индексу, дальнейшие изменения могут быть более легко введены, не входя в изменение любого номера индекса:
from collections import namedtuple Point = namedtuple('Point', 'name x y z') # addition of the field 'name' origin = Point('O', 0, 0, 0) A = Point('A', 1, 1, 1) B = Point('B', 1, 1, 0) C = Point('C', 1, 0, 0) D = Point('D', 1, 0, 1) for p in (origin, A, B, C, D): print(p) print(p.name) # more readable than p[0] that is no more the x coordinate print('x:', p.x, ' y:', p.y, ' z:', p.z) # unchanged print('x:', p[1], ' y:', p[2], ' z:', p[3]) # changed print()
Перечисление - это способ связать символические имена с константой значения и классифицировать их как определенный набор. Мы определяем перечисление путем создания класса, производного от перечисление и IntEnum, в зависимости от ценностей, которые мы хотим, чтобы наши константы имели: enum представляет собой универсальный вариант, IntEnum обеспечивает тот факт, что каждая константа будет иметь тип int.
Например, перечисления хороши для определения цветов по имени, определенным целочисленным типам, полу или, опять же, - в более общем смысле - элементам, принадлежащим к определенному типу. набор.
from enum import Enum, IntEnum, unique class Color_1(Enum): red = 'red' green = 'green' blue = 'blue' class Color_2(Enum): red = (255, 0, 0) green = (0, 255, 0) blue = (0, 0, 255) class Color_3(IntEnum): red = 0xFF0000 green = 0xFF00 blue = 0xFF class Gender_1(Enum): unknown = 'U' male = 'M' female = 'F' class Gender_2(Enum): unknown = 0.3 male = 0.5 female = 0.7 class Shape(Enum): # Note the different constants types, perfectly legal TRIANGLE = 't' RECTANGLE = 5 SQUARE = tuple('square') class DataType(IntEnum): int8 = -8 int16 = -16 int32 = -32 int64 = -64 int = -2 negative = -1 positive = 1 uint = 2 uint8 = 8 uint16 = 16 uint32 = 32 uint64 = 64
В питонском развитии - перечислениях элементам может быть присвоено определенное значение-которое может быть либо уникальным, либо нет, в зависимости от ваших предпочтений и спецификации. Декоратор unique используется для обеспечения уникальности значений. По умолчанию можно присвоить одно и то же постоянное значение двум или более различным символьным именам.
class Color_4(IntEnum): red = 1 green = 2 blue = 3 RED = 1 GREEN = 2 BLUE = 3
Перечисления элементов можно сравнивать между собой, но для того, чтобы они были успешными, необходимо не только значение совпадение, даже их тип должен быть одинаковым.
Например:
Color_4.red == Color_4.RED
Вернет True (тот же класс, то же значение), но следующее:
Shape.SQUARE == tuple('square')
Будет ложным, потому что правый элемент сравнения - кортеж ("квадрат") - не имеет типа Shape, хотя оба они имеют одинаковое значение.
В заключение отметим, что перечисления и безымянные числа - это разные инструменты.
Перечисления были добавлены совсем недавно на Python (поиск PEP435). Если память мне не изменяет правильно, namedtuples были доступны в течение довольно долгого времени, но я все еще новичок в сообществе, поэтому я могу ошибаться. HTH