什么是“改变”元组元素的优雅方式?

时间:2014-04-27 21:54:53

标签: python tuples

这很可能是某种东西的复制品,但是我的serach foo让我失望。

众所周知,元组是不可变的,所以你无法真正改变它们。但是,有时候,为了改变(1, 2, "three")(1, 2, 3)而做一些事情会很方便,或许与Haskell record update syntax.类似。你实际上不会改变原始元组,但你会得到一个 new 只有一个(或多个)元素不同的元素。

这样做的方法是:

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

我觉得将一个元组更改为一个列表但是有点违背了使用old_tuple的元组类型开头的目的:如果你使用的是列表,那么你就不必构建一个每次操作内存中元组的丢弃列表副本。

如果你要更改,比如说,只改变元组的第3个元素,你也可以这样做:

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

...但是如果您想要更改的是最后一个,或者 n -th到最后一个元素,则它不起作用。它还会创建一个抛弃列表(others)。它还会强制您将所有元素命名为 n -th。

有更好的方法吗?

1 个答案:

答案 0 :(得分: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也支持索引,因此您可以使用它们代替普通元组。

如果必须使用普通元组,只需使用辅助函数:

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

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