Python:タプルの値を変更する


123

私はPythonが初めてなので、この質問は少し基本的なものかもしれません。values次のタプルが呼び出されます。

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

275このタプルの最初の値(つまり)を変更したいのですが、タプルは不変なので、機能しvalues[0] = 200ません。どうすればこれを達成できますか?


24
タプルは不変です。これを実現するには、新しいタプルを作成する必要があります。
ハンターマクミレン2012

回答:


177

最初にあなたは尋ねる必要があります、なぜあなたはこれをしたいのですか?

ただし、次の方法で可能です。

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

しかし、物事を変更する必要がある場合は、おそらくそれを list


4
1つのユースケースは、値がめったに変更されない小さなシーケンスを多数格納しているが、場合によっては変更したい場合です。小さいがゼロではない長さのシーケンスの場合、タプル(1要素の場合は60バイト)とリスト(104バイト)のメモリ消費量が異なります。namedlistは本来存在しないため、別のユースケースはnamedtuplesです。
マイケルスコットカスバート

81
「なぜそれをしたいのか」という応答は、StackOverflowに不快感を与えます。オリジナルのポスターがそれを「したい」と思ってはいけません。実際、オリジナルのポスターがこのすべてをゼロから作成しているとは思わない方がいいでしょう。多くの場合、制御できない形式またはタイプの別のモジュールまたはデータソースからの出力を処理します。
rtphokie、

9
不変のコンテナーを変更したい(したがって、「なぜ」が非常に有効な質問である)@rtphokieは、タプルである可能性があるさまざまな形式を解釈することとは異なります。でもベントしてくれてありがとう:)
Jon Clements

7
リストに再キャストして一時変数を使用することは、不必要でメモリ効率が悪いようです。あなたは同じ名前のタプルにアンパックすることができます、そしてアンパックしながらupdateが必要なものは何でも更新できます。
ブライアンスピアリング2018年

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がすでに示したように、特定のインデックスでタプルの要素を置き換えるには、基本的に2つの方法があります。タプルをリストに変換するか、要素を置き換えて元に戻すか、または連結によって新しいタプルを作成します。

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これで3番目の要素のみをどのように変更しますか?
sdbbs

2
-ここでは、タプル内の任意の要素を変更することができる方法であるi = 2; values = (*values[:i], '300', *values[i+1:])
ブライアンSpiering

8

これは優れているわけではありませんが、もし誰かが興味を持っている場合は、次のように1行で実行できます。

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

それより速いですtuple = tuple(200 if i == 0 else _ for i, _ in enumerate(tuple))か?(なぜジェネレータの理解ではないのですか?)
匿名の

8

私はこれが技術的に質問に答えると信じていますが、家でこれをしないでください。現時点では、すべての回答には新しいタプルの作成が含まれますが、ctypesメモリ内でタプルを変更するために使用できます。64ビットシステムでのCPythonのさまざまな実装の詳細に依存して、これを行う1つの方法は次のとおりです。

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実装の詳細はいつでも警告なしに変更される可能性があり、タプルが互換性がないことに依存しているコードを破壊する可能性が高いため、これも信頼できません。さらに、タプルはPythonで最も軽量なコレクションオブジェクトであるため、新しいタプルを作成しても問題はありません。コレクションを頻繁に変更する必要がある場合は、代わりにリストを使用してください。
バクサウ

1
参照カウントを破棄する値にデクリメントするのを忘れました。漏れの原因になります。
wizzwizz4

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

編集:これは重複したエントリを持つタプルではまだ機能しません!!

プーヤのアイデアに基づいて:

これを頻繁に行うことを計画している場合(タプルは理由により不変であるため、これを行うべきではありません)、次のようなことを行う必要があります。

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

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

またはジョンのアイデアに基づいて:

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

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

3

最初に、なぜを変更したいのかを自問してくださいtuplePtyhon文字列とタプルが不変である理由があります。もしあなたがあなたを変異させたいならtuple、それはおそらくlist代わりにあるはずです。

次に、タプルを変更したい場合は、tupleをa listに変換してから変換し直し、新しいタプルを同じ変数に再度割り当てることができます。これは、タプルを1回だけ変更する場合に最適です。そうでなければ、個人的には直感に反すると思います。それは本質的には新しいタプルを作成しているので、タプルを変更したい場合は常に変換を実行する必要があるためです。また、コードを読んだ場合、なぜ単にを作成しないのかと考えると混乱するでしょうlist。しかし、ライブラリを必要としないため、これは素晴らしいことです。

mutabletuple 0.2mutabletuple(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。あなたがそうし、それが1回の操作である場合tuple、リストに変換し、それを変更listし、新しいtupleに変えて、oldを保持する変数に再度割り当てtupleます 欲望がtupleあり、どういうわけか回避しlist、複数回変異させたい場合は、を作成しますmutabletuple


2

基づいてジョンのアイデア、貴重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 2012

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

私はゲームに遅れましたが、(状況に応じて)最も簡単で、リソースを使いやすく、最も速い方法は、タプル自体を上書きすることだと思います。これにより、リストと変数を作成する必要がなくなり、1行でアーカイブされます。

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 19/12/30

はい-@patroqueeet、したがって、私はこのアプローチのマイナス面をはっきりと述べましたが、後で:...-。投票を再検討してください、ありがとう;)
GordanTrevis

1
ちょっと、再考してボタンをクリックしました。しかし、投票はSOによってロックされています:/
patroqueeet

0

tldr; 「回避策」は、実際には元のオブジェクトを変更するのではなく、新しいタプルオブジェクトを作成することです。

これは非常に古い質問ですが、誰かがこのPythonの変更タプルの狂気について教えてくれました。私は非常に驚いたり興味をそそられたり、ググリングをしたりして、ここに着陸しました(そして他の同様のサンプルをオンラインで)

私は私の理論を証明するためにいくつかのテストを実行しました

==値の等価性を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

そして、あなたはタプルを変更することができます: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)yをxに割り当てるだけです。
m4tx

2
また、「タプル」と「リスト」という名前を変数として使用すると、タプルとリストのタイプを後で比較するのが難しくなります。
マイケルスコットカスバート

-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
これらはタプルではなくリストであり、2番目の参照が指定されているかどうかに関係なく、とにかく変更できます。
Bachsau
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.