Python 中的子字符串.内存中的副本



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

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

子字符串的string_1string_2("深层")副本是否my_string或对内存中同一位置的引用?string_1string_2是否为my_string字符的完整副本分配内存?

请注意,我不是在问字符串的不变性。如果my_string很长,我想知道通过标记我的字符串来获取内存中的命中是什么。

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

通过查看 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] = '';

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

不同的Python实现(实际上是不同版本的CPython)的行为可能不同。例如,Jython可能使用java.lang.String,它不会制作副本。

Python 字符串是不可变的,所以在这种情况下,区别没有那么有意义,但它们是副本。 您无法对string_1string_2执行任何操作,都不会影响my_string的内容。

字符串在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

不确定它有多大帮助,甚至不能回答您的问题,但您可以使用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)

然后从那里开始...

最新更新