В чем разница между enum и namedtuple?

Я хотел бы знать, каковы различия между enum и namedtuple и когда следует использовать один над другим.

2 ответов


в качестве аналогии (хотя и несовершенной) вы можете подумать о enum.Enum и namedtuple в python как enum и struct В C. другими словами,enums-это способ сглаживания значений, в то время как namedtuple - это способ инкапсуляции данных по имени. Два не являются взаимозаменяемыми, и вы можете использовать enums как именованные значения в 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

вы часто не видим namedtupleS, как это, потому что то же самое может быть достигнуто с помощью более широко известных class декларации. The 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 это быстро структуры, которые с помощью __слот__ вместо _ _ dict__, завершает контент, который вы предоставляете при инициализации (который практически становится только для чтения, Хотя существует метод _replace ()).

namedtuple обычно используется, когда вам нужно много (например, сотни, тысячи и даже миллионы) объектов одного типа или Вы читаете и/или пишете запись.
Например, часто приводимый пример-это точка namedtuple, которая может использоваться для работы с вершиной многоугольника с ее x, y, z компоненты.
накладные расходы, введенные namedtuple над обычным кортежем, минимальны по сравнению с преимуществом всегда указывать на правильный компонент по имени (.икс. ,год. ,Зет. ,..) вместо индекса (0, 1, 2, ...).
Чтение кода, такого как A. x, проще, чем a[0]: значение очевидно, даже через несколько месяцев после написания кода и, лучше для других программистов.

таким образом, 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()

An перечисление - это способ связать символические имена с постоянными значениями и классифицировать их как определенный набор. Мы определяем перечисление, создавая класс, производный от любого перечисление или 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

в pythonic development-перечисления элементы могут иметь определенное значение, которое может быть уникальным или нет, в зависимости от ваших предпочтений и спецификаций. The уникальный декоратор используется для обеспечения уникальности значений. По умолчанию можно присвоить одно и то же постоянное значение двум или более различным символам имена.

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')

будет False-потому что правый элемент сравнения-кортеж ('square') - не имеет формы типа, хотя оба они имеют одинаковый значение.

в заключение, перечисления и namedtuples являются различными инструментами.

перечисления были добавлены совсем недавно в Python (поиск PEP435). Если мне не изменяет память, namedtuples были доступны довольно долго, но я все еще новичок в сообществе, поэтому я могу ошибаться. HTH