Python : 튜플의 값 변경


124

나는 파이썬을 처음 사용 하므로이 질문은 약간 기본적 일 수 있습니다. values다음을 포함 하는 튜플 이 있습니다.

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

275이 튜플 의 첫 번째 값 (예 :)을 변경하고 싶지만 튜플이 변경 불가능하므로 values[0] = 200작동하지 않는다는 것을 이해합니다 . 이것을 어떻게 할 수 있습니까?


24
튜플은 불변 이므로이를 위해서는 새로운 튜플을 만들어야합니다.
Hunter McMillen

답변:


178

먼저 물어볼 필요가 있습니다. 왜 이것을하고 싶습니까?

그러나 다음을 통해 가능합니다.

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

하지만 변경해야 할 경우에는 그대로 유지하는 것이 좋습니다. list


4
한 가지 사용 사례는 값이 거의 변경되지 않지만 원하는 경우가 거의없는 많은 수의 작은 시퀀스를 저장하는 경우입니다. 작지만 길이가 0이 아닌 시퀀스의 경우 튜플 (1 요소의 경우 60 바이트)과 목록 (104 바이트)의 메모리 소비가 차이를 만듭니다. 또 다른 사용 사례는 namedlist가 기본적으로 존재하지 않기 때문에 namedtuples입니다.
Michael Scott Cuthbert

81
"왜 그렇게 하시겠습니까?"라는 응답이 StackOverflow에서 나를 미치게 만듭니다. 원래 포스터가 그렇게하고 싶다고 가정하지 마십시오. 사실, 원본 포스터가이 모든 것을 처음부터 만들고 있다고 가정하지 않는 것이 더 나은 방법입니다. 더 자주 우리는 제어 할 수없는 형식 또는 유형의 다른 모듈 또는 데이터 소스의 출력을 처리합니다.
rtphokie

9
불변의 컨테이너를 변경하려는 @rtphokie (따라서 "왜"는 매우 유효한 질문 임)는 튜플 일 수있는 다른 형식을 해석하는 것과 다릅니다. 그래도 환기 해 주셔서 감사합니다 :)
Jon Clements

7
목록으로 다시 변환하고 임시 변수를 사용하는 것은 불필요하고 메모리 비효율적 인 것 같습니다. 같은 이름의 튜플에 압축을 풀고 업데이트가 필요한 모든 업데이트를 압축 해제 할 수 있습니다.
Brian Spiering

5
@JonClements 당신은 이것을하는 것이 나쁜 습관이라는 매우 귀중한 지적을합니다. 그것은 당신의 대답에 있어야 합니다. 그러나 수사 학적 질문은 종종 불필요하게 경멸적인 것으로 해석됩니다. 이러한 정보는 다음과 같은 형식으로 더 잘 구성됩니다. "이것은 나쁜 관행입니다 ..." 또는 "정말로 필요한 경우 신중하게 고려하십시오. 일반적으로 다음과 같은 이유로 설계에 결함이 있음을 암시합니다."
Philip Couling

74

문제에 따라 슬라이싱은 정말 깔끔한 솔루션이 될 수 있습니다.

>>> 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)

이를 통해 여러 요소를 추가하거나 일부 요소를 대체 할 수 있습니다 (특히 "이웃"인 경우). 위의 경우 목록으로 캐스팅하는 것이 더 적절하고 읽기 쉽습니다 (슬라이싱 표기법이 훨씬 더 짧더라도).


24

글쎄, 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

따라서 튜플이 짧으면 슬라이스하고 연결하십시오. 길면 목록 변환을 수행하십시오!


1
@ErikAronesty 항상 그런 것은 아닙니다. 한 번 유용한 경우는 변경할 수없고 첫 번째 요소 만 변경하려는 튜플을 메서드에서 반환하는 클래스를 확장하는 것입니다. return (val,) + res [1 :]은 res2 = list (res); res2 [0] = val; 반환 튜플 (RES2)
yucer

9

하나의 라이너로 가능합니다.

values = ('275', '54000', '0.0', '5000.0', '0.0')
values = ('300', *values[1:])

1
values이것으로 세 번째 요소 만 어떻게 변경 하시겠습니까?
sdbbs 2010 년

2
다음은 튜플의 모든 요소를 변경할 수있는 방법입니다 -i = 2; values = (*values[:i], '300', *values[i+1:])
브라이언 Spiering

8

이것이 우월하다는 것은 아니지만 누군가가 궁금하다면 다음과 같이 한 줄로 할 수 있습니다.

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

그게 더 빠릅 tuple = tuple(200 if i == 0 else _ for i, _ in enumerate(tuple))니까? (왜 발전기 이해가 안 되는가?)
Anonymous

8

나는 이것이 기술적으로 질문에 대한 답이라고 믿지만 집에서 이것을하지 마십시오. 현재 모든 답변에는 새 튜플 생성이 포함되지만 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

1
평소 답변과 다른 것을 아는 것이 항상 좋습니다. 건배!
Kartheek Palepu

C로 코딩하려는 사람들은 아마 정확히 그렇게해야합니다. 그렇게 통역사를 해킹하면 여기서 주제를 놓칠뿐입니다. 또한 cPython 구현 세부 사항이 경고없이 언제든지 변경 될 수 있으며 튜플에 의존하는 코드가 변경되지 않을 가능성이 있기 때문에 신뢰할 수 없습니다. 또한 튜플은 파이썬에서 가장 가벼운 컬렉션 객체이므로 새로 만드는 데 문제가 없습니다. 컬렉션을 자주 수정해야하는 경우에는 대신 목록을 사용하십시오.
Bachsau

1
버릴 값으로 참조 카운트를 줄이는 것을 잊었습니다. 그것은 누출을 일으킬 것입니다.
wizzwizz4 19

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')

3

편집 : 중복 항목이있는 튜플에서는 아직 작동하지 않습니다 !!

Pooya의 아이디어를 바탕으로 :

이 작업을 자주 할 계획이라면 (튜플이 불변하는 이유 때문에 그렇게해서는 안됩니다) 다음과 같이해야합니다 :

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

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

또는 Jon의 아이디어를 기반으로 :

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

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

3

먼저, tuple. 이유가 문자열과 튜플 Ptyhon에 불변은 당신이 당신의 돌연변이하려는 경우, tuple다음 아마해야한다 list대신합니다.

둘째, 여전히 튜플을 변경하려면를로 변환 tuplelist다음 다시 변환하고 새 튜플을 동일한 변수에 다시 할당 할 수 있습니다. 이 중대하다 당신이 한 번만 튜플을 돌연변이 위하여려고하는 경우에 . 그렇지 않으면 개인적으로 그것이 반 직관이라고 생각합니다. 본질적으로 새 튜플을 생성하기 때문에 튜플을 변경하려면 매번 변환을 수행해야합니다. 또한 코드를 읽으면 왜 생성하지 않는지 생각하는 것이 혼란 스러울 것입니다 list. 그러나 라이브러리가 필요하지 않기 때문에 좋습니다.

나는 mutabletuple 0.2를 사용 mutabletuple(typename, field_names, default=MtNoDefault)하는 것이 좋습니다 . 개인적으로이 방법이 더 직관적 이고 읽기 쉽다고 생각합니다 . 코드를 읽는 개인은 작성자가 앞으로이 튜플을 변경하려고한다는 것을 알 것입니다. 위 의 변환 방법 과 비교할 때 단점은 추가 py 파일을 가져와야한다는 것입니다.list

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, old를 보유하는 변수에 다시 할당하십시오 tuple. 욕망 tuple과 어떤 식 으로든 피하고 list두 번 이상 돌연변이를 원하면 mutabletuple.


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")

이전 값 발생을 모두 변경합니다.


여러 값을 변경하는 경우 (더 나은 단어가 없기 때문에) 상당히 불편할 것입니다. 그러나 다시 한 번 튜플을 수정하려는 이유는 무엇입니까?
Trufa

@Trufa 그래, 나는 그것을 작성하려고 해요 : D
Pooya

메서드 이름 modify_tuple_by_index가 정확하지 않아 혼동을 일으킬 수 있습니다.
msw

1

당신은 할 수 없습니다. 변경하려면 튜플 대신 목록을 사용해야합니다.

대신 새 값을 첫 번째 요소로 갖는 새 튜플을 만들 수 있습니다.


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 = 튜플 반복, 필요에 따라 각 항목 변경

그것이 개념입니다.


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')

이것은 길이가 알려진 정적 튜플 인 경우에만 작동합니다. 하지 코드는 대부분 빨리 실패하거나 것입니다 나중에는 너무 구체적 때문에 ...
patroqueeet

예-@patroqueeet, 따라서 나는 But : ...- 이후에이 접근 방식의 단점을 분명히 밝혔습니다. 귀하의
반대표를

1
이봐, 다시 생각하고 버튼을 클릭했습니다. 그러나 투표는 이제 SO에 의해 잠겨 있습니다 : /
patroqueeet

0

tldr; "해결 방법"은 실제로 원본을 수정하지 않고 새 튜플 객체를 만드는 것입니다.

이것은 매우 오래된 질문이지만 누군가가 파이썬 돌연변이 튜플 광기에 대해 나에게 말했습니다. 나는 매우 놀랐거나 흥미로 웠고 인터넷 검색을하면서 여기에 도착했습니다 (및 다른 유사한 샘플 온라인)

내 이론을 증명하기 위해 몇 가지 테스트를 실행했습니다.

참고 ==는 가치 평등을 is수행 하는 반면 참조 평등은 수행합니다 (obj a는 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

0

튜플의 항목은 수정할 수 없지만 튜플에서 변경 가능한 객체의 속성은 수정할 수 있습니다 (예 : 해당 객체가 목록 또는 실제 클래스 객체 인 경우).

예를 들면

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')

-2

나는 이걸했다:

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

변경하려면

list[0]=6

그리고 u는 튜플을 변경할 수 있습니다 : 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]

2
튜플은 튜플이 아니라 목록입니다. x = (y)x에 y를 할당합니다.
m4tx

2
또한 "tuple"및 "list"라는 이름을 변수로 사용하면 나중에 튜플과 목록 유형을 비교하기 어렵게됩니다.
Michael Scott Cuthbert

-4

참조로 복사를 사용하여 튜플의 값을 변경할 수 있습니다.

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

>>> tuple2=tuple1

>>> tuple2
    [20, 30, 40]

>>> tuple2[1]=10

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

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

1
두 번째 참조 여부에 관계없이 어쨌든 변경할 수있는 튜플이 아니라 목록입니다.
Bachsau
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.