2016-11-16 14 views
9

Tôi muốn biết sự khác nhau giữa enum và namedtuple là gì và khi nào nên sử dụng cái kia.Sự khác nhau giữa enum và namedtuple là gì?

+1

Op nên tìm kiếm một chút trước khi yêu cầu. Xem các chủ đề này: http://stackoverflow.com/questions/2970608/what-are-named-tuples-in-python và http://stackoverflow.com/questions/36932/how-can-i-represent-an -enum-in-python – Kiogara

Trả lời

12

Là một loại suy (mặc dù một là liều thuốc vạn), bạn có thể nghĩ enum.Enumnamedtuple trong python như enumstruct trong C. Nói cách khác, enum s là một cách để các giá trị răng cưa, trong khi namedtuple là một cách để đóng gói dữ liệu theo tên. Cả hai không thực sự hoán đổi cho nhau và bạn có thể sử dụng enum s làm giá trị được đặt tên trong một namedtuple.

Tôi nghĩ ví dụ này minh họa sự khác biệt.

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) 

Bạn có thể truy cập vào tên là "thuộc tính" của con người giống như cách bạn sẽ là một đối tượng thường xuyên.

>>> print(bert.name) 
Bert 
>>> print(bert.age) 
5 
>>> print(bert.hair_color) 
HairColor.black 
>>> print(bert.hair_color.value) 
3 

Bạn thường không thấy namedtuple s như thế này bởi vì các khái niệm cơ bản tương tự có thể được thực hiện bằng cách sử dụng biết đến rộng rãi hơn class khai. Định nghĩa class bên dưới hoạt động gần như giống hệt với định nghĩa namedtuple ở trên.

class Person: 
    def __init__(self, name, age, hair_color): 
     self.name = name 
     self.age = age 
     self.hair_color = hair_color 

Tuy nhiên, một sự khác biệt lớn giữa một namedtuple và một đối tượng class là các thuộc tính của một namedtuple không thể thay đổi sau khi tạo nó.

+2

Bạn cũng có thể sử dụng 'namedtuple' làm giá trị cho một enum ...' class People (enum.Enum): john = Person ('John', 21, HairColor.blonde) ' – Bakuriu

7

Các namedtuple là một cấu trúc nhanh rằng, sử dụng __slots__ thay vì __dict__, để hoàn tất nội dung mà bạn cung cấp lúc khởi tạo (mà thực tế trở nên chỉ đọc, mặc dù một phương pháp _replace() tồn tại).

Tên thường được sử dụng khi bạn cần nhiều đối tượng (như hàng trăm, hàng nghìn và thậm chí hàng triệu) cùng loại hoặc bạn đang đọc và/hoặc ghi một bản ghi.
Ví dụ, một ví dụ thường được trích dẫn là một điểm têntuple có thể được sử dụng để làm việc với một đỉnh đa giác với các thành phần x, y, z của nó.
Chi phí được giới thiệu bởi một bộ tên trên một bộ thông thường là tối thiểu nếu so sánh với lợi ích của việc luôn trỏ đến đúng thành phần theo tên (.x, .y, .z, ...) thay vì theo chỉ mục (0, 1, 2, ...).
Đọc mã như A.x dễ hơn A [0]: nghĩa là hiển nhiên, thậm chí vài tháng sau khi bạn đã viết mã và, tốt hơn, cho các lập trình viên khác.

Do đó, tên tệp nhanh, có thể được sử dụng để xác định có ý nghĩa nội dung của bộ và, nhưng cuối cùng nhưng không kém phần quan trọng, có thể cùng tồn tại với mã cũ truy cập vào nội dung theo chỉ mục.

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

Đi vào từ ví dụ trên, ngay sau khi tất cả mọi thứ đang truy cập các thành phần điểm bằng tên thay vì theo chỉ số, thay đổi hơn nữa có thể được dễ dàng hơn được giới thiệu, bằng cách không đi sâu vào việc thay đổi bất kỳ số chỉ số:

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 liệt kê là cách để ghép đôi các tên biểu tượng thành các giá trị không đổi và phân loại chúng thành một tập hợp cụ thể. Chúng ta định nghĩa một kiểu liệt kê bằng cách tạo một lớp bắt nguồn từ Enum hoặc IntEnum, tùy thuộc vào các giá trị mà chúng ta muốn hằng số của chúng ta có: Enum là phiên bản chung, IntEnum thực thi thực tế là mọi giá trị không đổi sẽ là kiểu int.

Ví dụ, enums là tốt để xác định màu sắc theo tên, loại số nguyên cụ thể, giới tính, hoặc, một lần nữa, - nói chung hơn - yếu tố thuộc về một tập hợp cụ thể.

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 

Phát triển pythonic - các phần tử liệt kê có thể có giá trị cụ thể được chỉ định - có thể là duy nhất hay không, tùy theo sở thích và đặc điểm của bạn. Trình trang trí độc đáo được sử dụng để thực thi các giá trị độc đáo. Theo mặc định, có thể chỉ định cùng một giá trị không đổi cho hai hoặc nhiều tên biểu tượng khác nhau.

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

Enumerations yếu tố có thể được so sánh với nhau, nhưng đối với họ để thành công, không chỉ phải trận đấu có giá trị, thậm chí loại của họ phải giống nhau.

Ví dụ:

Color_4.red == Color_4.RED 

sẽ trở lại Đúng (cùng lớp, cùng một giá trị), nhưng điều sau đây:

Shape.SQUARE == tuple('square') 

sẽ False - bởi vì các yếu tố bên phải của sự so sánh - tuple ('square') - không thuộc loại Shape, mặc dù cả hai đều có cùng giá trị.

Để kết luận, enums và namedtuples là các công cụ khác nhau.

Các số đếm đã được thêm gần đây vào Python (tìm kiếm PEP435). Nếu bộ nhớ phục vụ cho tôi đúng, tên gọi đã có sẵn trong một thời gian dài, nhưng tôi vẫn là một newbie cộng đồng, do đó tôi có thể sai. HTH

+0

Và ngược lại để enums? – Billy

+0

@Billy xin lỗi, nhưng bạn đã đến đây trong khi tôi đang viết phần thứ hai tôi vừa thêm vào lúc này. –

+0

Từ thử nghiệm trên với 'IntEnum' tôi đã nhận thấy rằng so sánh sau đây' Color_4.red == 1' kết quả trong 'True'. Tuy nhiên, khi thực hiện '1 trong Color_4', kết quả là' False' (chỉ khi thực hiện 'Color_4.red in Color_4' sẽ dẫn đến' True') – Marc

Các vấn đề liên quan