Enumとnamedtupleの違いは何ですか、またどちらを使用する必要があるのかを知りたいです。
類推として(不完全ではありますが)、enum.Enum
およびnamedtuple
in python as Cのenum
およびstruct
と考えることができます。つまり、enum
sは値をエイリアスする方法です、namedtuple
は名前でデータをカプセル化する方法です。この2つは実際には互換性がなく、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
sが表示されないことがよくあります。以下の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はfast構造であり、__ 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