我是python的新手,所以这个问题可能有点基础.我有一个名为的元组values,其中包含以下内容:
('275', '54000', '0.0', '5000.0', '0.0')
Run Code Online (Sandbox Code Playgroud)
我想更改275此元组中的第一个值(即),但我知道元组是不可变的,所以values[0] = 200不起作用.我怎样才能做到这一点?
Jon*_*nts 145
首先你需要问,你为什么要这样做?
但它可以通过:
t = ('275', '54000', '0.0', '5000.0', '0.0')
lst = list(t)
lst[0] = '300'
t = tuple(lst)
Run Code Online (Sandbox Code Playgroud)
但是如果你需要改变一些东西,你可能最好还是把它当成一个 list
Dav*_*ter 60
根据您的问题切片可能是一个非常简洁的解决方案:
>>> 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)
Run Code Online (Sandbox Code Playgroud)
这允许您添加多个元素或者也可以替换一些元素(特别是如果它们是"邻居".在上面的情况下,转换为列表可能更合适和可读(即使切片符号更短).
sja*_*obi 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:]
...:
Run Code Online (Sandbox Code Playgroud)
那么,哪种方法更好,那就更快?
事实证明,对于短元组(在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
Run Code Online (Sandbox Code Playgroud)
然而,如果我们看一下更长的元组,列表转换是要走的路:
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
Run Code Online (Sandbox Code Playgroud)
对于很长的元组,列表转换要好得多!
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
Run Code Online (Sandbox Code Playgroud)
此外,连接方法的性能取决于我们替换元素的索引.对于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
Run Code Online (Sandbox Code Playgroud)
所以:如果你的元组很短,切片和连接.如果它很长,请进行列表转换!
正如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')
Run Code Online (Sandbox Code Playgroud)
并不是说这是优越的,但是如果任何人好奇的话,可以通过以下方法完成:
tuple = tuple([200 if i == 0 else _ for i, _ in enumerate(tuple)])
Run Code Online (Sandbox Code Playgroud)
我相信这从技术上讲可以回答问题,但不要在家中这样做。目前,所有答案都涉及创建一个新的元组,但是您可以使用它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
Run Code Online (Sandbox Code Playgroud)
它是使用idoimatic Python的简单方法:
values = ('275', '54000', '0.0', '5000.0', '0.0')
values = ('300', *values[1:])
Run Code Online (Sandbox Code Playgroud)