2017-08-30 102 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)}