web-dev-qa-db-ja.com

列挙型と名前付きタプルの違いは何ですか?

Enumとnamedtupleの違いは何ですか、またどちらを使用する必要があるのか​​を知りたいです。

26
Carlos Afonso

類推として(不完全ではありますが)、enum.Enumおよびnamedtuple in python as Cのenumおよびstructと考えることができます。つまり、enumsは値をエイリアスする方法です、namedtupleは名前でデータをカプセル化する方法です。この2つは実際には互換性がなく、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

よく知られているnamedtuple宣言を使用することで同じ基本的な概念を実現できるため、このようなclasssが表示されないことがよくあります。以下の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の属性は作成後に変更できないことです。

27
Billy

namedtuplefast構造であり、__ dict __の代わりに__ slots __を使用して、初期化時に提供するコンテンツを完成させます( _replace()メソッドは存在しますが、実際には読み取り専用になります)。

名前付きタプルは通常、同じタイプのオブジェクトが多数(数百、数千、さらには数百万など)必要な場合、またはレコードの読み取りや書き込みを行う場合に使用されます。
たとえば、よく引用される例は、x, y, zコンポーネントを持つポリゴンの頂点を操作するために使用されるタプルという名前のポイントです。
名前によって正しいコンポーネントを常に指すという利点と比較すると、通常のタプルよりも名前付きタプルによってもたらされるオーバーヘッドは最小限です(.x、.y、.z、.. 。)インデックスではなく(0、1、2、...)。
A.xなどのコードの読み取りは、A [0]よりも簡単です。意味は、コードを作成してから数か月後でも明らかで、他のプログラマにとっても同様です。

したがって、namedtupleは高速であり、Tupleのコンテンツを有意義に識別するために使用できます。また、インデックスによってTupleコンテンツにアクセスする古いコードと共存できます。

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

列挙は、シンボリック名を定数値に結合し、それらを特定のセットとして分類する方法です。定数に必要な値に応じて、Enumまたは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開発では-列挙要素には特定の値が割り当てられている可能性があります-設定や仕様に応じて、一意の値である場合とそうでない場合があります。 niqueデコレータは、値の一意性を強制するために使用されます。デフォルトでは、同じ定数値を2つ以上の異なるシンボリック名に割り当てることができます。

class Color_4(IntEnum):
    red = 1
    green = 2
    blue = 3
    RED = 1
    GREEN = 2
    BLUE = 3

Enumerations要素は互いに比較できますが、それらが成功するためには、値が一致する必要があるだけでなく、型が同じである必要があります。

例えば:

Color_4.red == Color_4.RED

true(同じクラス、同じ値)を返しますが、次のようになります。

Shape.SQUARE == Tuple('square')

falseになります-比較の正しい要素-Tuple( 'square')-はShapeタイプではありませんが、両方とも同じ値です。

結論として、列挙型と名前付きタプルは異なる手段です。

列挙が最近追加されましたPython(search PEP435))。メモリが適切である場合、namedtupleはかなり長い間利用可能でしたが、私はまだコミュニティ初心者なので、間違っている可能性があります。HTH

16
Alberto Vassena