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?
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
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).
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!
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
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')
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)])
C'est un one-liner simple utilisant Python idiomatique:
values = ('275', '54000', '0.0', '5000.0', '0.0')
values = ('300', *values[1:])
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 list
et vouloir muter plusieurs fois, créez alors mutabletuple
.
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")
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')
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.
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.