假设我在 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_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_1
和string_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)
然后从那里开始...