@ Ответ Гейба верен, но его нужно показывать четко, а не выдвигать гипотезы.
CPython (и, вероятно, только CPython) добавляет строку на месте, когда это возможно.Есть ограничения на то, когда он может сделать это.
Во-первых, он не может сделать это для интернированных строк.Вот почему вы никогда не увидите этого, если протестируете с a = "testing"; a = a + "testing"
, потому что назначение строкового литерала приводит к интернированной строке.Вы должны создать строку динамически, как этот код делает с str(12345)
.(Это не является большим ограничением; после того, как вы добавите этот способ один раз, result будет неинтернизированной строкой, поэтому, если вы добавляете строковые литералы в цикл, это произойдет только в первый раз.)
Во-вторых, Python 2.x делает это только для str
, а не unicode
.Python 3.x делает это для строк Unicode.Это странно: разница в производительности - разница в сложности .Это препятствует использованию строк Unicode в 2.x, когда они должны поощрять его к переходу на 3.x.
И, наконец, не может быть никаких других ссылок на строку.
>>> a = str(12345)
>>> id(a)
3082418720
>>> a += str(67890)
>>> id(a)
3082418720
Это объясняет, почему не-Unicode версия намного быстрее в вашем тесте, чем Unicode-версия.
Фактический код для этого string_concatenate
в Python/ceval.c
и работает для обоих s1 = s1 + s2
и s1 += s2
.Функция _PyString_Resize
в Objects/stringobject.c
также прямо говорит: Следующая функция нарушает представление о том, что строки неизменны .Смотри также http://bugs.python.org/issue980695.