2017-08-30 83 views
4

我想在Python中创建一组namedtuple,并且可以使用union操作动态添加元素。python set union操作与名称元组表现不好

以下代码片段会创建一个的namedtuple,该行为很好。

from collections import namedtuple 

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

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

如果我创建另一个namedtuple,并将其与union操作如预期它不表现添加到我的set它打印

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

现在。

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都显示相同的行为。

回答

1

union期望一个集合(或者一个列表或另一个可迭代的),但是你传递一个命名的元组,它本身是一个可迭代的元素,但它提供了值,所以你将该集合与值合并。试试这个:

s = s.union({b3}) 
3

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

但是,你想要的是把namedtuple在另一个容器/迭代,因此合并与包含在新的父项目(namedtuple)进行迭代:

s.union((b3,)) 

变得如果更明显你真的认为运营商相当于:

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

相比于我们真正想要的:

s = s | {b3} 

联合与外迭代执行。

1

由于b3是可迭代的,因此union工作在其元素而不是元组本身上。替换成:

s = s.union([b3]) 
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)}