就地for循环中的Python字符串连接?

标签 python string

我知道 Python 字符串是不可变的,这意味着

letters = "world"
letters += "sth"
连接后会给我一个不同的字符串对象
begin: id(letters): 1828275686960
end: id(letters): 1828278265776
但是,当我运行 for 循环附加到字符串时,结果是字符串对象在 for 循环期间保持不变:
letters = "helloworld"
print("before for-loop:")
print(id(letters))
print("in for-loop")

for i in range(5):
    letters += str(i)
    print(id(letters))
输出:
before for-loop:
2101555236144
in for-loop
2101557044464
2101557044464
2101557044464
2101557044464
2101557044464
显然是 letter 的底层字符串对象指向在 for 循环期间没有改变,这与字符串应该是不可变的概念相矛盾。
这是 Python 在幕后执行的某种优化吗?

最佳答案

来自 documentation :

id(object)

Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

CPython implementation detail: This is the address of the object in memory.


方法id()在这种情况下,存储的字符串的内存地址为 source code向我们展示:
static PyObject *
builtin_id(PyModuleDef *self, PyObject *v)
/*[clinic end generated code: output=0aa640785f697f65 input=5a534136419631f4]*/
{
    PyObject *id = PyLong_FromVoidPtr(v);

    if (id && PySys_Audit("builtins.id", "O", id) < 0) {
        Py_DECREF(id);
        return NULL;
    }

    return id;
} 
发生的事情是两个对象的生命结束和开始确实重叠。
Python 保证字符串的不变性,只要它们还活着。
article @kris 建议显示:
import _ctypes
    
a = "abcd"
a += "e"

before_f_id = id(a)

a += "f"

print(a)
print( _ctypes.PyObj_FromPtr(before_f_id) ) # prints: "abcdef"
字符串 a结束是生命并且不保证可以恢复给定内存位置,实际上上面的例子表明它是重复使用 对于新变量。
我们可以看看它是如何实现的under the hoodunicode_concatenate查看最后几行代码的方法:
res = v;
PyUnicode_Append(&res, w);
return res;
哪里vw是表达式中的那些:v += w方法PyUnicode_Append实际上是试图为新对象重用相同的内存位置,in detailPyUnicode_Append :
PyUnicode_Append(PyObject **p_left, PyObject *right):

...

new_len = left_len + right_len;

if (unicode_modifiable(left)
    ...
{
    /* append inplace */
    if (unicode_resize(p_left, new_len) != 0)
        goto error;

    /* copy 'right' into the newly allocated area of 'left' */
    _PyUnicode_FastCopyCharacters(*p_left, left_len, right, 0, right_len);
}

关于就地for循环中的Python字符串连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69556269/

相关文章:

python - scikit-learn 中逻辑回归的输入格式与 R 中一样

string - 从文本中提取特定字符串

android - 动态获取应用程序的可用语言

java - 检查一个字符串是否与其他两个字符串交错

regex - Sublime Text : Regex to convert Uppercase to Title Case?

python - 使用 Sphinx Autodoc 时模拟内部模块

Python sympy.Plot - OverflowError : int too large to convert to float

python - 使用装饰器参数进行切换

python - 根据条件转换 Pandas 数据框列

c# - 快速字符串到 byte[] 的转换