102 votes

Si les chaînes Python sont immuables, pourquoi gardent-elles le même identifiant si j'utilise += pour les ajouter ?

En Python, les chaînes de caractères sont immuables, ce qui signifie que leur valeur ne peut pas être modifiée. Cependant, lors de l'ajout à la chaîne dans l'exemple suivant, il semble que la mémoire de la chaîne originale soit modifiée puisque l'identifiant reste le même :

>>> s = 'String'
>>> for i in range(5, 0, -1):
...     s += str(i)
...     print(f"{s:<11} stored at {id(s)}")
... 
String5     stored at 139841228476848
String54    stored at 139841228476848
String543   stored at 139841228476848
String5432  stored at 139841228476848
String54321 stored at 139841228476848

A l'inverse, dans l'exemple suivant, l'id change :

>>> a = "hello"
>>> id(a)
139841228475760
>>> a = "b" + a[1:]
>>> print(a)
bello
>>> id(a)
139841228475312

125voto

ShadowRanger Points 44

Il s'agit d'une optimisation spécifique à CPython pour le cas où l'option str Il se trouve que l'annexe n'a pas d'autres références vivantes. L'interpréteur "triche" dans ce cas, ce qui lui permet de modifier la chaîne existante en réallouant (ce qui peut être en place, selon la disposition du tas) et en ajoutant les données directement, et en réduisant souvent le travail de manière significative dans les boucles qui concaténent de manière répétée (ce qui le fait se comporter davantage comme la méthode amortie O(1) les ajouts d'un list plutôt que O(n) opérations de copie à chaque fois). Elle n'a pas d'effet visible en dehors du fait que le id Il est donc légal de le faire (personne n'ayant une référence existante à un str ne le voit jamais changer, à moins que le str était logiquement remplacée).

Vous n'êtes pas censé vous y fier (les interprètes qui ne comptent pas les références ne peuvent pas utiliser cette astuce, puisqu'ils ne peuvent pas savoir si l'élément str a d'autres références), par La toute première recommandation de programmation du PEP8 :

Le code doit être écrit de manière à ne pas désavantager les autres implémentations de Python (PyPy, Jython, IronPython, Cython, Psyco, etc.).

Par exemple, ne vous fiez pas à l'implémentation efficace par CPython de la concaténation de chaînes de caractères sur place pour les déclarations de la forme a += b o a = a + b . Cette optimisation est fragile même dans CPython (elle ne fonctionne que pour certains types) et n'est pas du tout présente dans les implémentations qui n'utilisent pas le refcounting. Dans les parties de la bibliothèque sensibles aux performances, la fonction ''.join() doit être utilisé à la place. Cela garantira que la concaténation s'effectue en temps linéaire entre les différentes implémentations.

Si vous voulez casser l'optimisation, il y a toutes sortes de façons de le faire, par exemple en changeant votre code en :

>>> while i!=0:
...     s_alias = s  # Gonna save off an alias here
...     s += str(i)
...     print(s + " stored at " + str(id(s)))
...     i -= 1
... 

l'interrompt en créant un alias, en augmentant le nombre de références et en indiquant à Python que la modification sera visible ailleurs que dans le fichier s Il ne peut donc pas l'appliquer. De même, un code comme :

s = s + a + b

ne peut pas l'utiliser, car s + a se produit en premier, et produit un temporaire qui b doit alors être complétée, plutôt que de remplacer immédiatement le s et l'optimisation est trop fragile pour essayer de gérer cela. Un code presque identique comme :

s += a + b

ou :

s = s + (a + b)

rétablit l'optimisation en s'assurant que la concaténation finale est toujours une concaténation où s est l'opérande de gauche et le résultat est utilisé pour remplacer immédiatement s .

44voto

Mark Tolonen Points 32702

Indépendamment des détails de mise en œuvre, le documents dire :

Deux objets dont les durées de vie ne se chevauchent pas peuvent avoir la même valeur id().

L'objet précédent référencé par s n'existe plus après que le += Le nouvel objet n'enfreint donc aucune règle en ayant la même id .

4voto

YKT Points 49

Si les objets ont des durées de vie qui ne se chevauchent pas, leurs valeurs d'identification peuvent être identiques, mais si les variables ont des durées de vie qui se chevauchent, elles doivent avoir des valeurs d'identification différentes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X