Python:改变元组中的值

时间:2012-07-12 18:27:43

标签: python tuples

我是python的新手,所以这个问题可能有点基础。我有一个名为values的元组,其中包含以下内容:

('275', '54000', '0.0', '5000.0', '0.0')

我想更改此元组中的第一个值(即275),但我知道元组是不可变的,因此values[0] = 200将无效。我怎样才能做到这一点?

17 个答案:

答案 0 :(得分:128)

首先你要问,你为什么要这样做?

但是可以通过:

t = ('275', '54000', '0.0', '5000.0', '0.0')
lst = list(t)
lst[0] = '300'
t = tuple(lst)

但是如果你需要改变一些东西,你可能最好把它保留为list

答案 1 :(得分:55)

根据您的问题,切片可能是一个非常简洁的解决方案:

>>> b = (1, 2, 3, 4, 5)
>>> b[:2] + (8,9) + b[3:]
(1, 2, 8, 9, 4, 5)
>>> b[:2] + (8,) + b[3:]
(1, 2, 8, 4, 5)

这允许您添加多个元素或者也可以替换一些元素(特别是如果它们是"邻居"。在上面的情况下,转换到列表可能更合适和可读(即使切片)符号要短得多)。

答案 2 :(得分:18)

好吧,正如Trufa已经表明的那样,基本上有两种方法可以替换给定索引处的元组元素。将元组转换为列表,替换元素并转换回来,或者通过连接构造新的元组。

In [1]: def replace_at_index1(tup, ix, val):
   ...:     lst = list(tup)
   ...:     lst[ix] = val
   ...:     return tuple(lst)
   ...:

In [2]: def replace_at_index2(tup, ix, val):
   ...:     return tup[:ix] + (val,) + tup[ix+1:]
   ...:

那么,哪种方法更好,也就是更快?

事实证明,对于短元组(在Python 3.3上),连接实际上更快!

In [3]: d = tuple(range(10))

In [4]: %timeit replace_at_index1(d, 5, 99)
1000000 loops, best of 3: 872 ns per loop

In [5]: %timeit replace_at_index2(d, 5, 99)
1000000 loops, best of 3: 642 ns per loop

然而,如果我们看一下更长的元组,列表转换是可行的方法:

In [6]: k = tuple(range(1000))

In [7]: %timeit replace_at_index1(k, 500, 99)
100000 loops, best of 3: 9.08 µs per loop

In [8]: %timeit replace_at_index2(k, 500, 99)
100000 loops, best of 3: 10.1 µs per loop

对于很长的元组,列表转换要好得多!

In [9]: m = tuple(range(1000000))

In [10]: %timeit replace_at_index1(m, 500000, 99)
10 loops, best of 3: 26.6 ms per loop

In [11]: %timeit replace_at_index2(m, 500000, 99)
10 loops, best of 3: 35.9 ms per loop

此外,连接方法的性能取决于我们替换元素的索引。对于list方法,索引无关紧要。

In [12]: %timeit replace_at_index1(m, 900000, 99)
10 loops, best of 3: 26.6 ms per loop

In [13]: %timeit replace_at_index2(m, 900000, 99)
10 loops, best of 3: 49.2 ms per loop

所以:如果您的元组很短,则切片并连接。 如果很长,请进行列表转换!

答案 3 :(得分:6)

正如Hunter McMillen在评论中所写,元组是不可变的,你需要创建一个新的元组才能实现这一目标。例如:

>>> tpl = ('275', '54000', '0.0', '5000.0', '0.0')
>>> change_value = 200
>>> tpl = (change_value,) + tpl[1:]
>>> tpl
(200, '54000', '0.0', '5000.0', '0.0')

答案 4 :(得分:4)

我相信这在技术上回答了这个问题,但不要在家里这样做。目前,所有答案都涉及创建新元组,但您可以使用ctypes修改内存中的元组。在64位系统上依赖CPython的各种实现细节,一种方法如下:

def modify_tuple(t, idx, new_value):
    # `id` happens to give the memory address in CPython; you may
    # want to use `ctypes.addressof` instead.
    element_ptr = (ctypes.c_longlong).from_address(id(t) + (3 + idx)*8)
    element_ptr.value = id(new_value)
    # Manually increment the reference count to `new_value` to pretend that
    # this is not a terrible idea.
    ref_count = (ctypes.c_longlong).from_address(id(new_value))
    ref_count.value += 1

t = (10, 20, 30)
modify_tuple(t, 1, 50)   # t is now (10, 50, 30)
modify_tuple(t, -1, 50)  # Will probably crash your Python runtime

答案 5 :(得分:4)

并不是说这是优越的,但如果有人好奇,可以在一行上完成:

tuple = tuple([200 if i == 0 else _ for i, _ in enumerate(tuple)])

答案 6 :(得分:3)

这是使用idoimatic Python的简单方法:

gc

答案 7 :(得分:2)

您不能修改元组中的项目,但是可以修改元组中可变对象的属性(例如,如果这些对象是列表或实际的类对象)

例如

my_list = [1,2]
tuple_of_lists = (my_list,'hello')
print(tuple_of_lists) # ([1, 2], 'hello')
my_list[0] = 0
print(tuple_of_lists) # ([0, 2], 'hello')

答案 8 :(得分:2)

首先,问问自己为什么要改变你的tuplestrings and tuple are immutable in Ptyhon 的原因,如果你想改变你的tuple,那么它应该是list

其次,如果您仍希望改变元组,那么您可以将tuple转换为list然后将其转换回来,并将新元组重新分配给同一个变量。如果你只想改变你的元组一次,这很棒。否则,我个人认为这是违反直觉的。因为它本质上是创建一个新的元组,并且每次如果你想改变元组,你都必须执行转换。另外,如果您阅读代码,那么为什么不创建list会让人感到困惑?但这很好,因为它不需要任何库。

我建议使用mutabletuple 0.2中的mutabletuple(typename, field_names, default=MtNoDefault)。我个人认为这种方式是更直观可读。个人阅读代码会知道编写者打算在将来改变这个元组。上面的list转换方法的缺点是,这需要您导入其他py文件。

from mutabletuple import mutabletuple

myTuple = mutabletuple('myTuple', 'v w x y z')
p = myTuple('275', '54000', '0.0', '5000.0', '0.0')
print(p.v) #print 275
p.v = '200' #mutate myTuple
print(p.v) #print 200

TL; DR :不要试图改变tuple。如果你这样做并且它是一次性操作将tuple转换为列表,则将其变异,将list转换为新的tuple,然后重新分配给持有旧tuple的变量}。如果欲望tuple并且以某种方式想要避免list并想要多次变异,那么请创建mutabletuple

答案 9 :(得分:2)

编辑:这对有重复条目的元组不起作用!!

基于Pooya's idea

如果你打算经常这样做(你不应该这样做,因为元组由于某种原因是无法改变的)你应该做这样的事情:

def modTupByIndex(tup, index, ins):
    return tuple(tup[0:index]) + (ins,) + tuple(tup[index+1:])

print modTupByIndex((1,2,3),2,"a")

或基于Jon's idea

def modTupByIndex(tup, index, ins):
    lst = list(tup)
    lst[index] = ins
    return tuple(lst)

print modTupByIndex((1,2,3),1,"a")

答案 10 :(得分:2)

基于Jon的想法和亲爱的Trufa

def modifyTuple(tup, oldval, newval):
    lst=list(tup)
    for i in range(tup.count(oldval)):
        index = lst.index(oldval)
        lst[index]=newval

    return tuple(lst)

print modTupByIndex((1, 1, 3), 1, "a")

它会更改所有旧值的出现次数

答案 11 :(得分:0)

我发现编辑元组的最佳方法是使用以前的版本作为基础来重新创建元组。

这是我用来制作浅色版本的一个例子(当时我已经打开了它):

colour = tuple([c+50 for c in colour])

它做了什么,它是通过元组颜色'并读取每个项目,对其执行某些操作,最后将其添加到新元组中。

所以你想要的是:

values = ('275', '54000', '0.0', '5000.0', '0.0')

values  = (tuple(for i in values: if i = 0: i = 200 else i = values[i])

具体的那个不起作用,但这个概念就是你所需要的。

tuple = (0, 1, 2)
  

tuple =遍历元组,根据需要更改每个项目

这个概念。

答案 12 :(得分:0)

我来晚了,但我认为最简单,资源友好且最快的方式(取决于情况), 是覆盖元组本身。由于这将消除对列表和变量创建的需要,因此将其归档在一行中。

new = 24
t = (1, 2, 3)
t = (t[0],t[1],new)

>>> (1, 2, 24)

但是:这仅适用于较小的元组,并且还会将您限制为固定的元组值,不过,无论如何,在大多数情况下,这都是元组的情况。

因此在这种特殊情况下,它看起来像这样:

new = '200'
t = ('275', '54000', '0.0', '5000.0', '0.0')
t = (new, t[1], t[2], t[3], t[4])

>>> ('200', '54000', '0.0', '5000.0', '0.0')

答案 13 :(得分:0)

tldr; “解决方法”是创建一个新的元组对象,而不是实际上修改原始的

尽管这是一个非常老的问题,但是有人告诉我有关Python变异元组的疯狂。我非常惊讶/被它吸引,并做了一些谷歌搜索,我降落在这里(和其他在线的类似样本)

我进行了一些测试以证明我的理论

请注意,==进行值相等,而is进行参照相等(obj是与obj b相同的实例)

a = ("apple", "canana", "cherry")
b = tuple(["apple", "canana", "cherry"])
c = a

print("a: " + str(a))
print("b: " + str(b))
print("c: " + str(c))
print("a == b :: %s" % (a==b))
print("b == c :: %s" % (b==c))
print("a == c :: %s" % (a==c))
print("a is b :: %s" % (a is b))
print("b is c :: %s" % (b is c))
print("a is c :: %s" % (a is c))

d = list(a)
d[1] = "kiwi"
a = tuple(d)

print("a: " + str(a))
print("b: " + str(b))
print("c: " + str(c))
print("a == b :: %s" % (a==b))
print("b == c :: %s" % (b==c))
print("a == c :: %s" % (a==c))
print("a is b :: %s" % (a is b))
print("b is c :: %s" % (b is c))
print("a is c :: %s" % (a is c))

收益:

a: ('apple', 'canana', 'cherry')
b: ('apple', 'canana', 'cherry')
c: ('apple', 'canana', 'cherry')
a == b :: True
b == c :: True
a == c :: True
a is b :: False
b is c :: False
a is c :: True
a: ('apple', 'kiwi', 'cherry')
b: ('apple', 'canana', 'cherry')
c: ('apple', 'canana', 'cherry')
a == b :: False
b == c :: True
a == c :: False
a is b :: False
b is c :: False
a is c :: False

答案 14 :(得分:0)

你做不到。如果要更改它,则需要使用列表而不是元组。

请注意,您可以改为创建一个以新值作为其第一个元素的新元组。

答案 15 :(得分:-2)

我这样做了:

list = [1,2,3,4,5]
tuple = (list)

并改变,只需做

list[0]=6

你可以改变一个元组:D

这里是完全从IDLE

复制的
>>> list=[1,2,3,4,5,6,7,8,9]

>>> tuple=(list)

>>> print(tuple)

[1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> list[0]=6

>>> print(tuple)

[6, 2, 3, 4, 5, 6, 7, 8, 9]

答案 16 :(得分:-2)

您可以使用引用复制来更改元组的值

>>> tuple1=[20,30,40]

>>> tuple2=tuple1

>>> tuple2
    [20, 30, 40]

>>> tuple2[1]=10

>>> print(tuple2)
    [20, 10, 40]

>>> print(tuple1)
    [20, 10, 40]