Python中的子串。内存中的副本?

时间:2012-12-04 19:20:48

标签: python regex string immutability

假设我在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_2my_string(“深”)副本或内存中相同位置的引用是什么? string_1string_2my_string中的字符的完整副本分配内存吗?

请注意,我没有询问字符串的不变性。如果my_string 很长,我想知道我通过标记字符串来获取内存中的内容。

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

4 个答案:

答案 0 :(得分: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,它不会复制。

答案 1 :(得分: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

答案 2 :(得分:1)

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

答案 3 :(得分: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)

然后从那里开始......