web-dev-qa-db-fra.com

Python: changement de valeur dans un tuple

Je suis nouveau sur python alors cette question est peut-être un peu élémentaire. J'ai un tuple appelé values qui contient les éléments suivants:

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

Je veux changer la première valeur (c'est-à-dire 275) dans ce tuple, mais je comprends que les n-uplets sont immuables, donc values[0] = 200 ne fonctionnera pas. Comment puis-je atteindre cet objectif?

94
Dawood

Vous devez d’abord demander pourquoi vous voulez faire cela.

Mais c'est possible via:

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

Mais si vous devez changer des choses, vous feriez probablement mieux de le garder comme un list

137
Jon Clements

En fonction de votre problème, le découpage en tranches peut être une solution vraiment intéressante:

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

Cela vous permet d’ajouter plusieurs éléments ou de remplacer quelques éléments (surtout s’ils sont des "voisins". Dans ce cas, il est probablement plus approprié de lire une liste et de la lire (même si la notation de découpage est beaucoup plus courte).

56
Dave Halter

Comme Trufa l’a déjà montré, il existe essentiellement deux façons de remplacer un élément de Tuple à un indice donné. Convertissez le tuple en une liste, remplacez l'élément et reconvertissez-le ou construisez un nouveau tuple par concaténation.

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:]
   ...:

Alors, quelle méthode est la meilleure, c'est-à-dire plus rapide?

Il s'avère que pour les petits nuplets (sur Python 3.3), la concaténation est en réalité plus rapide!

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

Cependant, si nous examinons des n-uplets plus longs, la conversion de liste est la voie à suivre:

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

Pour les très longs tuples, la conversion de liste est nettement meilleure!

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

En outre, les performances de la méthode de concaténation dépendent de l'index auquel nous remplaçons l'élément. Pour la méthode de liste, l'index n'est pas pertinent.

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

Donc: Si votre tuple est court, découpez et concaténez. S'il est long, convertissez la liste!

18
sjakobi

Je crois que cela répond techniquement à la question, mais ne le faites pas à la maison. Pour le moment, toutes les réponses impliquent la création d'un nouveau tuple, mais vous pouvez utiliser ctypes pour modifier un tuple en mémoire. En se basant sur divers détails de mise en œuvre de CPython sur un système 64 bits, une façon de procéder est la suivante:

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
6
fuglede

Comme Hunter McMillen l’a écrit dans ses commentaires, les n-uplets étant immuables, vous devez créer un nouveau Tuple pour y parvenir. Par exemple:

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

Ce n’est pas supérieur, mais si vous êtes curieux, vous pouvez le faire sur une seule ligne avec:

Tuple = Tuple([200 if i == 0 else _ for i, _ in enumerate(Tuple)])
6
bphi

C'est un one-liner simple utilisant Python idiomatique:

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

Frist, demandez-vous pourquoi vous voulez muter votre Tuple. Il y a une raison pour laquelle les chaînes et le tuple sont immuables dans Ptyhon, si vous voulez muter votre Tuple, il devrait probablement l'être un list à la place.

Deuxièmement, si vous souhaitez toujours muter votre tuple, vous pouvez convertir votre Tuple en list, puis le reconvertir et réaffecter le nouveau tuple à la même variable. C’est génial si vous ne modifiez votre tuple qu’une seule fois . Sinon, je pense personnellement que cela est contre-intuitif. Car il s’agit essentiellement de créer un nouveau tuple et chaque fois que vous souhaitez muter le tuple, vous devez effectuer la conversion. Aussi, si vous lisez le code, il serait déroutant de penser pourquoi ne pas simplement créer un list? Mais c’est bien parce qu’il ne nécessite aucune bibliothèque.

Je suggère d'utiliser mutabletuple(typename, field_names, default=MtNoDefault) de mutabletuple 0.2 . Personnellement, je pense que cette façon de faire est plus intuitive et lisible. Le personnel En lisant le code, vous saurez que l'auteur a l'intention de transformer ce tuple à l'avenir. L'inconvénient est que, par rapport à la méthode de conversion list ci-dessus, vous devez importer un fichier py supplémentaire.

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 : N'essayez pas de muter Tuple. Si vous le faites et qu’il s’agit d’une opération unique, convertissez Tuple en liste, modifiez-la, transformez list en un nouveau Tuple et réaffectez-le à la variable conservant l’ancien Tuple. Si vous désirez Tuple et que vous voulez d'une manière ou d'une autre éviter listet vouloir muter plusieurs fois, créez alors mutabletuple.

2
OLIVER.KOO

basé sur Jon 's Idea et cher 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")

cela change toutes vos anciennes occurrences de valeurs

2
Pooya

EDIT: Cela ne fonctionne pas encore sur les n-uplets avec des entrées en double !!

Basé sur idée de Pooya :

Si vous envisagez de le faire souvent (ce qui ne devrait pas être le cas, les tuples étant immuables pour une raison), vous devriez faire quelque chose comme ceci:

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

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

Ou basé sur idée de Jon :

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

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

Je suis en retard mais je pense que le le plus simple, le moyen le plus rapide et le plus pratique pour les ressources ((selon la situation)), consiste à écraser le Tuple lui-même. Dans la mesure où cela supprimerait la nécessité de créer une liste et une variable, il est archivé sur une ligne.

new = 24
t = (1, 2, 3)
t = (t[0],t[1],new)

>>> (1, 2, 24)

Mais: Ceci n'est utile que pour les n-uplets plutôt petits et vous limite également à une valeur de n-uplet fixe, néanmoins, c'est le cas pour les n-uplets la plupart du temps de toute façon.

Donc, dans ce cas particulier, cela ressemblerait à ceci:

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

Tu ne peux pas. Si vous voulez le changer, vous devez utiliser une liste au lieu d'un tuple.

Notez que vous pouvez créer un nouveau tuple dont le premier élément est la nouvelle valeur.

0
BrenBarn

J'ai trouvé le meilleur moyen de modifier les nuplets est de recréer le nuplet en utilisant la version précédente comme base.

Voici un exemple que j'ai utilisé pour créer une version plus claire d'une couleur (je l'avais déjà ouverte à l'époque):

colour = Tuple([c+50 for c in colour])

Ce qu'il fait, c'est qu'il passe par la "couleur" du tuple et lit chaque élément, y fait quelque chose et l'ajoute finalement au nouveau tuple.

Donc, ce que vous voudriez être quelque chose comme:

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

values  = (Tuple(for i in values: if i = 0: i = 200 else i = values[i])

Ce spécifique ne fonctionne pas, mais le concept est ce dont vous avez besoin.

Tuple = (0, 1, 2)

Tuple = itérer sur Tuple, modifier chaque élément selon les besoins

c'est le concept.

0
Aedus