[python] Python : 튜플의 값 변경

나는 파이썬을 처음 사용 하므로이 질문은 약간 기본적 일 수 있습니다. 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')