나는 파이썬을 처음 사용 하므로이 질문은 약간 기본적 일 수 있습니다. values
다음을 포함 하는 튜플 이 있습니다.
('275', '54000', '0.0', '5000.0', '0.0')
275
이 튜플 의 첫 번째 값 (예 :)을 변경하고 싶지만 튜플이 변경 불가능하므로 values[0] = 200
작동하지 않는다는 것을 이해합니다 . 이것을 어떻게 할 수 있습니까?
답변
먼저 물어볼 필요가 있습니다. 왜 이것을하고 싶습니까?
그러나 다음을 통해 가능합니다.
t = ('275', '54000', '0.0', '5000.0', '0.0')
lst = list(t)
lst[0] = '300'
t = tuple(lst)
하지만 변경해야 할 경우에는 그대로 유지하는 것이 좋습니다. list
답변
문제에 따라 슬라이싱은 정말 깔끔한 솔루션이 될 수 있습니다.
>>> 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)
이를 통해 여러 요소를 추가하거나 일부 요소를 대체 할 수 있습니다 (특히 “이웃”인 경우). 위의 경우 목록으로 캐스팅하는 것이 더 적절하고 읽기 쉽습니다 (슬라이싱 표기법이 훨씬 더 짧더라도).
답변
글쎄, 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
또한 연결 방법의 성능은 요소를 대체하는 인덱스에 따라 달라집니다. 목록 방법의 경우 색인은 관련이 없습니다.
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
따라서 튜플이 짧으면 슬라이스하고 연결하십시오. 길면 목록 변환을 수행하십시오!
답변
하나의 라이너로 가능합니다.
values = ('275', '54000', '0.0', '5000.0', '0.0')
values = ('300', *values[1:])
답변
이것이 우월하다는 것은 아니지만 누군가가 궁금하다면 다음과 같이 한 줄로 할 수 있습니다.
tuple = tuple([200 if i == 0 else _ for i, _ in enumerate(tuple)])
답변
나는 이것이 기술적으로 질문에 대한 답이라고 믿지만 집에서 이것을하지 마십시오. 현재 모든 답변에는 새 튜플 생성이 포함되지만 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
답변
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')