2013-03-10 132 views
10

我正在处理namedtuples的列表。我想在每个已经创建的名称元组中添加一个字段。看来我可以通过将它作为一个属性来引用它(如在namedtuple.attribute = 'foo'中那样),但是它不会被添加到字段列表中。如果我不在田野名单上做任何事情,我有什么理由不这样做?有没有更好的方法来添加一个字段?如何将字段添加到namedtuple?

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

为什么你不使用字典? dict.keys肯定会添加'字段'。 – omikron 2014-09-02 11:34:55

回答

10

你做什么工作,因为namedtuple(...)返回新类。要实际获取Result对象,请实例化该类。所以,正确的做法是:

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

,你会发现,添加属性,这些对象不工作。所以你不应该这样做的原因是因为它不起作用。只有滥用类对象才行,我希望我不需要详细说明为什么这是一个可怕的,可怕的想法。

请注意,无论您是否可以向namedtuples添加属性(即使列出了您事先需要的所有属性),也无法在其创建后更改namedtuple对象。元组是不可变的。因此,如果您需要在创建后出于任何原因(以任何方式或形状)更改对象,则不能使用namedtuple。你最好定义一个自定义类(一些namedtuple为你添加的东西甚至对可变对象没有意义)。

2

定义它后,您不能在namedtuple中添加新字段。唯一的方法是创建一个新模板并创建新的namedtuple实例。

分析

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

result不是一个元组,但它创建的元组的类。

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

您创建一个新的记录是这样的:

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

>>> p.x 
1 

打印在px

>>> p.x = 5 

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

这将引发错误,因为元组是不可改变的。

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

这不会改变任何东西。

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

这也没有改变任何东西。

解决方案

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

请注意,在这里您正在修改命名元组的type,而不是该类型的实例。在这种情况下,你可能想从旧创建一个新的类型与其他字段:

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

如:

​​
0

您可以轻松地串联namedtuples,记住他们是不可变的

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)