python 集合并集操作在命名元组中表现不佳

python set union operation is not behaving well with named tuples

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

以下代码片段创建了 namedtupleset,表现良好。

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 并使用 union 操作将其添加到我的 set,它不会按预期运行。

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 都表现出相同的行为。

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

s = s.union({b3})

一个namedtuple实例是一个可迭代的项目。 set.union 只是将当前集合与 namedtuple 中的项目合并。

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

s.union((b3,))

如果你真的想到等价的运算符就更明显了:

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

与我们实际想要的相比:

s = s | {b3}

union 与外部迭代一起执行。

因为 b3 是可迭代的,所以 union 作用于它的元素而不是元组本身。将其替换为:

s = s.union([b3])

set.union 上的文档实际上是这样解释的:

union(*others)

Return a new set with elements from the set and all 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)}