3

假设我在 Python 中有一个字符串my_string,并且我根据以下内容对其进行标记some_pattern

match.re.search(some_pattern, my_string)
string_1 = match.group(1)
string_2 = match.group(2)
....

string_1子字符串的和string_2(“深”)副本是否在内存中my_string或对内存中相同位置的引用?为 ?中的字符的完整副本执行string_1并分配内存?string_2my_string

请注意,我不是在询问字符串的不变性。如果my_string,我想知道通过标记我的字符串对内存的影响是什么。

我不需要确切知道重用了多少内存,但是知道字符串的标记化是否最终会复制内存肯定会很有用。

4

4 回答 4

3

通过查看 Python 2.7.3 源代码,获取字符串切片会复制字符数据:

Objects/stringobject.c

string_slice()调用以下函数PyString_FromStringAndSize()

/* Inline PyObject_NewVar */
op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size);
if (op == NULL)
    return PyErr_NoMemory();
PyObject_INIT_VAR(op, &PyString_Type, size);
op->ob_shash = -1;
op->ob_sstate = SSTATE_NOT_INTERNED;
if (str != NULL)
    Py_MEMCPY(op->ob_sval, str, size);
op->ob_sval[size] = '\0';

这里,str是指向字符数据的指针,size是长度。注意 malloc 和 memcpy。

不同的 Python 实现(以及不同版本的 CPython)可能表现不同。例如,Jython 可能使用java.lang.String,它不会进行复制。

于 2012-12-04T19:38:07.037 回答
1

字符串在 python 中是不可变的,因此子字符串只是新对象。

In [7]: str="foobar"

In [8]: id(str)
Out[8]: 140976032

In [10]: id(str[:4])
Out[10]: 141060224

返回的子字符串对象与原始字符串对象相同的唯一情况是string==substring

In [16]: foo="foobar"

In [17]: id(foo)
Out[17]: 140976032

In [18]: id(foo[:])
Out[18]: 140976032

In [19]: foo="foobar"*10000   # huge string

In [20]: id(foo)
Out[20]: 141606344

In [21]: id(foo[:])
Out[21]: 141606344
于 2012-12-04T19:22:53.190 回答
1

Python 字符串是不可变的,因此在这种情况下区别没有多大意义,但它们是副本。您无能为力,string_1string_2不会影响my_string.

于 2012-12-04T19:23:02.510 回答
0

不确定它有多大帮助甚至回答你的问题,但你可以使用finditer然后只根据需要对原始字符串进行切片......

>>> import re
>>> string = 'abcdefhijkl'
>>> matches = list(re.finditer('.' , string))
>>> dir(matches[0])
['__class__', '__copy__', '__deepcopy__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'end', 'endpos', 'expand', 'group', 'groupdict', 'groups', 'lastgroup', 'lastindex', 'pos', 're', 'regs', 'span', 'start', 'string']
>>> matches[0].span()
(0, 1)

然后从那里去...

于 2012-12-04T19:40:22.787 回答