在 Python 中对不可变对象进行操作时,如何创建新对象?

When operating on immutable objects in Python, how is the new object created?

提问人:bhp 提问时间:4/13/2020 更新时间:4/13/2020 访问量:156

问:

我知道不可变的对象不能就地更改。将创建一个新对象并将其重新分配给相同的变量名称。通过这种方式,我们可以保持与变量的关联。在内部,变量指向不同的对象。

>>> string = 'object'
>>> old_id = id(string)
>>> old_id
4452633584
>>> string = 'new' + string
>>> new_id = id(string)
>>> new_id
4501338544
>>> old_id == new_id
False

在上面的例子中,Python 是否创建一个可的克隆来连接到 ,然后,在重新赋值之前使这个新对象不可变?string'new'string

我不明白不能就地改变的物体也可以被手术。

难道 Python 不需要改变一个可变的东西来产生一个新东西吗?如果我想在一块木头上钉子,但那块木头是不可改变的,我怎么会得到一块锤子?

python-3.x 不变性 可变

评论

0赞 aartist 4/13/2020
看起来该字符串变量提供值“object”,并且与“new”和字符串变量连接,根据您的代码重新分配此新值。因此,它是 python 字符串添加值,而不是操作实际的字符串对象。

答:

3赞 mkrieger1 4/13/2020 #1

不变性是语言层面的一个概念。该语言指定,一旦创建字符串对象,实现不会为您提供修改该字符串对象的工具。

实现本身可能具有内部工具,用于在创建字符串时对其进行修改,然后才能访问字符串。

例如,在 CPython 字符串实现中,字符串连接是通过创建一个具有新大小的空对象来执行的,该对象在内部表示字符串。然后,在返回对象之前,将两个原始字符串中的字符复制到中:PyUnicode

PyObject *
PyUnicode_Concat(PyObject *left, PyObject *right)
{
    PyObject *result;
    /* […] */
    Py_ssize_t left_len, right_len, new_len;

    /* […] */

    left_len = PyUnicode_GET_LENGTH(left);
    right_len = PyUnicode_GET_LENGTH(right);

    /* […] */

    result = PyUnicode_New(new_len, maxchar);
    /* […] */
    _PyUnicode_FastCopyCharacters(result, 0, left, 0, left_len);
    _PyUnicode_FastCopyCharacters(result, left_len, right, 0, right_len);
    /* […] */
    return result;
}

如果我想在一块木头上钉子,但那块木头是 不可改变,我怎么会得到一块锤击过的木头?

在这个类比中,这意味着你得到了一块木头,里面已经有钉子了,但你没有得到一把锤子。语言实现已经为你钉上了钉子,但你不能假设它是如何做到的。它可能用了锤子,或者它可能在钉子周围长了一棵树。