2014-04-27 98 views
2

這很可能是一些東西的重複,但我的serach foo讓我失望。什麼是「改變」元組元素的優雅方式?

它是衆所周知的元組是不可變的,所以你不能真的改變它們。然而,有時候,可能需要做一些改變的工作,比如(1, 2, "three")(1, 2, 3),或許與Haskell record update syntax.類似,但實際上並沒有改變原始元組,但是你會得到一個新的只有一個(或更多)元素不同。

的一種方式去這樣做,這將是:

elements = list(old_tuple) 
elements[-1] = do_things_to(elements[-1]) 
new_tuple = tuple(elements) 

我覺得改變一個元組列表,但是那種違背了使用的元組類型old_tuple開始與目的:如果你是使用列表來代替,您不必在每個操作的內存中構建元組丟棄列表副本。

如果你要改變,比方說,只是一個元組的第三個元素,你也可以這樣做:

def update_third_element(a, b, c, *others): 
    c = do_things_to(c) 
    return tuple(a, b, c, *others) 

new_tuple = update_third_element(*old_tuple) 

這將抵制在元組中的元素數量的變化比幼稚的做法更好:

a, b, c, d, e, f, g, h, i, j = old_tuple 
c = do_things_to(c) 
new_tuple = (a, b, c, d, e, f, g, h, j, j) # whoops 

...但它不工作,如果你想改變是最後一個,或ñ列到最後一個元素。它還創建一個扔掉列表(others)。它也迫使你命名所有元素,最多爲n -th。

有沒有更好的方法?

+3

你說,「改變一個元組的列表但是那種違背了使用的元組類型的宗旨,爲'old_tuple'到首先」。事實上,需要改變一個元素就是破壞了使用元組類型開始的目的。如果你發現自己需要改變元組的元素,他們可能不應該首先是元組。如果你不需要經常這樣做,它可能會有點難看。 – BrenBarn

+0

@BrenBarn我不同意不可變性(如果你持有這個對象的引用,它永遠不會改變)意味着你不應該想要一個對象,並從中創建一個與原始對象略有不同的新對象。 – badp

+0

對於那些不相信的人來說,這個最好的例子當然是'str's,它有一個'替換'的方法,儘管它是不可變的。 – badp

回答

2

我會用collections.namedtuple代替:

>>> from collections import namedtuple 

>>> class Foo(namedtuple("Foo", ["a", "b", "c"])): 
     pass 

>>> f = Foo(1, 2, 3) # or Foo(a=1, b=2, c=3) 
>>> f._replace(a = 5) 
Foo(a=5, b=2, c=3) 

namedtuple S還支持索引,所以你可以將普通的元組的使用它們。

如果你必須使用一個普通的元組,只需使用一個輔助功能:

>>> def updated(tpl, i, val): 
     return tpl[:i] + (val,) + tpl[i + 1:] 

>>> tpl = (1, 2, 3) 
>>> updated(tpl, 1, 5) 
(1, 5, 3) 
+0

+1:'_replace'本質上是我正在尋找的元組方法;由於某種原因,'tuple'實際上並沒有它。 – badp

相關問題