2013-03-10 25 views
10

Tôi đang làm việc với danh sách tên đã đặt tên. Tôi muốn thêm một trường vào mỗi tuple được đặt tên sau khi nó đã được tạo. Có vẻ như tôi có thể làm điều đó bằng cách chỉ tham chiếu nó như là một thuộc tính (như trong namedtuple.attribute = 'foo'), nhưng sau đó nó không được thêm vào danh sách các trường. Có lý do nào khiến tôi không nên làm theo cách này nếu tôi không làm gì với danh sách các trường? Có cách nào tốt hơn để thêm trường?Tôi làm cách nào để thêm các trường vào một tập tin có tên?

>>> from collections import namedtuple 
>>> result = namedtuple('Result',['x','y']) 
>>> result.x = 5 
>>> result.y = 6 
>>> (result.x, result.y) 
(5, 6) 
>>> result.description = 'point' 
>>> (result.x, result.y, result.description) 
(5, 6, 'point') 
>>> result._fields 
('x', 'y') 
+0

Và tại sao bạn không sử dụng dict? dict.keys chắc chắn sẽ có thêm 'trường'. – omikron

Trả lời

10

Những gì bạn làm công trình vì namedtuple(...) trả về một lớp mới. Để thực sự có được một đối tượng Result, bạn khởi tạo lớp đó. Vì vậy, một cách chính xác là:

Result = namedtuple('Result', ['x', 'y']) 
result = Result(5, 6) 

Và bạn sẽ thấy rằng việc thêm thuộc tính cho các đối tượng này không không làm việc. Vì vậy, lý do bạn không nên làm điều đó là bởi vì nó không hoạt động. Chỉ lạm dụng các đối tượng lớp làm việc, và tôi hy vọng tôi không cần phải đi vào chi tiết tại sao đây là một ý tưởng kinh khủng, kinh khủng. Lưu ý rằng bất kể bạn có thể thêm thuộc tính vào tên đã đặt tên hay không (và thậm chí nếu bạn liệt kê tất cả các thuộc tính bạn cần trước đó), bạn không thể thay đổi đối tượng được đặt tên sau khi nó được tạo ra. Tuples là không thay đổi. Vì vậy, nếu bạn cần thay đổi các đối tượng sau khi tạo vì bất kỳ lý do gì, theo bất kỳ cách nào hoặc hình dạng nào, bạn không thể sử dụng namedtuple. Bạn nên định nghĩa một lớp tùy chỉnh (một số thứ mà bạn thêm namedtuple bổ sung cho bạn thậm chí không có ý nghĩa đối với các đối tượng có thể thay đổi).

2

Bạn không thể thêm trường mới vào namedtuple sau khi xác định. Cách duy nhất là tạo một mẫu mới và tạo các phiên bản namedtuple mới.

Phân tích

>>> from collections import namedtuple 
>>> result = namedtuple('Result',['x','y']) 
>>> result 
<class '__main__.Result'> 

result không phải là một tuple, nhưng lớp mà tạo ra các bộ.

>>> result.x 
<property object at 0x02B942A0> 

Bạn tạo một tuple mới như thế này:

>>> p = result(1, 2) 
>>> p 
Result(x=1, y=2) 

>>> p.x 
1 

In giá trị x trong p.

>>> p.x = 5 

Traceback (most recent call last): 
    File "<pyshell#10>", line 1, in <module> 
    p.x = 5 
AttributeError: can't set attribute 

Lỗi này ném vì bộ không thay đổi.

>>> result.x = 5 
>>> result 
<class '__main__.Result'> 
>>> result._fields 
('x', 'y') 
>>> p = result(1, 2) 
>>> p 
Result(x=1, y=2) 

Điều này không thay đổi gì cả.

>>> result.description = 'point' 
>>> result 
<class '__main__.Result'> 
>>> result._fields 
('x', 'y') 

Điều này cũng không thay đổi gì cả.

Giải pháp

>>> result = namedtuple('Result', ['x','y']) 
>>> p = result(1, 2) 
>>> p 
Result(x=1, y=2) 
>>> # I need one more field 
>>> result = namedtuple('Result',['x','y','z']) 
>>> p1 = result(1, 2, 3) 
>>> p1 
Result(x=1, y=2, z=3) 
>>> p 
Result(x=1, y=2) 
9

Lưu ý rằng tại đây bạn đang sửa đổi type của các bộ dữ liệu được đặt tên chứ không phải các trường hợp thuộc loại đó.Trong trường hợp này, bạn có thể muốn tạo ra một loại mới với một trường bổ sung từ một tuổi:

result = namedtuple('Result',result._fields+('point',)) 

ví dụ:

>>> result = namedtuple('Result',['x','y']) 
>>> result = namedtuple('Result',result._fields+('point',)) 
>>> result._fields 
('x', 'y', 'point') 
0

Bạn có thể dễ dàng nối namedtuples, hãy nhớ rằng họ là bất biến

from collections import namedtuple 

T1 = namedtuple('T1', 'a,b') 
T2 = namedtuple('T2', 'c,d') 

t1 = T1(1,2) 
t2 = T2(3,4) 

def sum_nt_classes(*args): 
    return namedtuple('_', ' '.join(sum(map(lambda t:t._fields, args),()))) 

def sum_nt_instances(*args): 
    return sum_nt_classes(*args)(*sum(args,())) 

print sum_nt_classes(T1,T2)(5,6,7,8) 
print sum_nt_instances(t1,t2) 
Các vấn đề liên quan