Python 如何将字段添加到命名元组?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15324644/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 19:49:30  来源:igfitidea点击:

how do I add fields to a namedtuple?

pythonnamedtuple

提问by rudivonstaden

I am working with a list of namedtuples. I would like to add a field to each named tuple after it has already been created. It seems I can do that by just referencing it as an attribute (as in namedtuple.attribute = 'foo'), but then it isn't added to the list of fields. Is there any reason why I shouldn't do it this way if I don't do anything with the fields list? Is there a better way to add a field?

我正在处理一个命名元组列表。我想在每个命名元组创建后添加一个字段。似乎我可以通过将它作为属性引用(如namedtuple.attribute = 'foo')来做到这一点,但随后它不会被添加到字段列表中。如果我不对字段列表做任何事情,有什么理由不应该这样做吗?有没有更好的方法来添加字段?

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

采纳答案by ATOzTOA

What you do works because namedtuple(...)returns a new class. To actually get a Result object, you instantiate that class. So the correct way is:

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

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

And you'll find that adding attributes to these objects does notwork. So the reason you shouldn't do it is because it doesn't work. Only abusing the class objects works, and I hope I don't need to go into detail why this is a horrible, horrible idea.

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

Note that regardless of whether you can add attributes to namedtuples or not (and even if you list all attributes you need beforehand), you cannot change a namedtuple object after it's created. Tuples are immutable. So if you need to change objects after creation for any reason, in any way or shape, you can't use namedtuple. You're better off defining a custom class (some of the stuff namedtupleadds for you doesn't even make sense for mutable objects).

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

回答by ATOzTOA

You cannot add a new field to a namedtupleafter defining it. Only way is to create a new template and creating new namedtupleinstances.

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

Analysis

分析

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

resultis not a tuple, but the class which creates tuples.

result不是元组,而是创建元组的类。

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

You create a new tuple like this:

你像这样创建一个新的元组:

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

>>> p.x
1

Prints the value xin p.

打印的价值xp

>>> p.x = 5

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

This throws error because tuple is immutable.

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

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

This doesn't change anything.

这不会改变任何事情。

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

This doesn't change anything either.

这也不会改变任何事情。

Solution

解决方案

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

回答by mgilson

Notice that here you're modifying the typeof the named tuples, not instances of that type. In this case, you'd probably want to create a new type with an additional field from the old one:

请注意,这里您正在修改type命名元组的 ,而不是该类型的实例。在这种情况下,您可能希望使用旧类型的附加字段创建一个新类型:

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

e.g.:

例如:

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

回答by Anton Ovsyannikov

You can easily concatenate namedtuples, keeping in mind that they are immutable

您可以轻松连接命名元组,记住它们是不可变的

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)