3

我想namedtuple在 python 中创建一组,能够使用联合操作动态添加元素。

下面的代码片段创建了一个setof namedtuple,它表现得很好。

from collections import namedtuple

B = namedtuple('B', 'name x')

b1 = B('b1',90)
b2 = B('b2',92)
s = set([b1,b2])
print(s)

哪个打印

{B(name='b1', x=90), B(name='b2', x=92)}

现在,如果我创建另一个namedtuple并将其添加到我setunion操作中,它的行为将不符合预期。

b3 = B('b3',93)
s = s.union(b3)
print(s)

代码片段打印以下输出。

{93, B(name='b1', x=90), B(name='b2', x=92), 'b3'}

预期的输出应该是:

{B(name='b1', x=90), B(name='b2', x=92), B(name='b3', x=93)}

我是否误解了 API?python2 和 3 都表现出相同的行为。

4

4 回答 4

4

namedtuple实例是项的可迭代。set.union简单地将当前集合与namedtuple.

但是,您想要的是将 放在namedtuple另一个容器/可迭代中,因此合并是使用namedtuple新父可迭代中包含的项目( )完成的:

s.union((b3,))

如果您实际上考虑等效的运算符,它会变得更加明显:

s = s | set(b3) # set(b3) -> {93, 'b3'}

与我们真正想要的相比:

s = s | {b3}

联合是使用外部可迭代执行的。

于 2017-08-30T14:00:41.283 回答
3

union需要一个集合(或一个列表或另一个可迭代对象),但您传递了一个命名元组,它本身就是一个可迭代对象,但它提供值,因此您将集合与值合并。尝试这个:

s = s.union({b3})
于 2017-08-30T14:00:15.787 回答
1

由于b3是可迭代的,union因此对其元素而不是元组本身起作用。将其替换为:

s = s.union([b3])
于 2017-08-30T14:00:45.143 回答
0

上的文档set.union实际上解释了这一点:

union(*others)

返回一个新集合,其中包含集合中的元素和所有其他元素。

因此,它将创建一个新集合,其中包括以下所有元素others

>>> set(b3)  # these are the unique elements in your `b3`
{93, 'b3'}

>>> s.union(b3)   # the union of the unique elements in "s" and "b3"
{B(name='b1', x=90), 93, 'b3', B(name='b2', x=92)}

在您的情况下(因为您将其分配回s),您可以简单地添加该项目,从而完全避免创建一个新集合:

>>> s.add(b3)
>>> s
{B(name='b1', x=90), B(name='b3', x=93), B(name='b2', x=92)}
于 2017-08-30T14:12:11.887 回答