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
.