2016-11-16 71 views
9

我想知道枚舉和namedtuple之間有什麼區別,以及何時應該使用一個。enum和namedtuple有什麼區別?

+1

在詢問之前,應該搜索一下。看看這些話題:http://stackoverflow.com/questions/2970608/what-are-named-tuples-in-python和http://stackoverflow.com/questions/36932/how-can-i-represent-an -enum-in-python – Kiogara

回答

12

作爲一個比喻(雖然不完美的),則可以想到在python enum.Enumnamedtupleenum和C. struct換句話說,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 

然而,namedtupleclass對象之間的主要區別在於,一個namedtuple的屬性不能創建後進行更改。

+2

你也可以使用'namedtuple's作爲enum的值...'class People(enum.Enum):john = Person('John',21,HairColor.blonde)' – Bakuriu

7

namedtuple是,使用__slots__代替__dict__一個快速結構,最終確定在初始化您提供的內容(即幾乎成爲只讀,雖然_replace()方法存在)。

當需要很多(如數百,數千甚至數百萬個)相同類型的對象或者您正在讀取和/或正在寫入記錄時,通常會使用namedtuple。
例如,一個經常被引用的例子是一個Point命名的元組,它可能被用來處理一個帶有x, y, z組件的多邊形頂點。
namedtuple在常規元組上引入的開銷是最小的,如果與總是用名稱(.x,.y,.z,...)而不是索引指向正確組件的好處相比, (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() 

枚舉是一種將符號名稱耦合到常量值並將它們分類爲特定集合的方法。我們通過創建從EnumIntEnum派生的類來定義枚舉,具體取決於我們希望常量所具有的值: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 

在Python的發展 - 枚舉元素可能會被分配一個特定的值 - 這可以是唯一的或不是,根據自己的喜好和規範。 獨特的裝飾器用於強制值的唯一性。默認情況下,可以將相同的常量值分配給兩個或更多不同的符號名稱。

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

將假 - 因爲比較合適的元素 - 元組( 'square') - 不是Shape類型,雖然它們都具有相同的值。

總之,枚舉和namedtuples是不同的工具。

最近剛剛向Python添加了枚舉(搜索PEP435)。如果記憶提供給我的權利,namedtuples可以使用很長時間,但我仍然是一個社區新手,因此我可能是錯的。 HTH

+0

並對比枚舉? – Billy

+0

@比利抱歉,當我寫下我剛剛添加的第二部分時,你來到這裏。 –

+0

從'IntEnum'測試上面我已經注意到,下面的比較'Color_4.red == 1'產生'True'。但是,在Color_4中執行'1'時,會導致'False'(只有在執行 'Color_4'中的Color_4.red時纔會導致'True') – Marc