这个问题在这里已经有了答案:
Does Python do slice-by-reference on strings?
(2 个回答)
10 个月前关闭。
我想知道是否:
a = "abcdef"
b = "def"
if a[3:] == b:
print("something")
确实执行了 a
的“def”部分的副本内存中的某个地方,或者字母检查是否就地完成?注意:我说的是一个字符串,而不是一个列表(我知道答案)
最佳答案
字符串切片在 CPython 中进行复制。
查看源码,这个操作是在 unicodeobject.c:unicode_subscript
中处理的.当 step 为 1,start 为 0,并且字符串的整个内容被切片时,显然有一种特殊情况可以重用内存 - 这进入 unicode_result_unchanged
并且不会有副本。但是,一般情况下调用 PyUnicode_Substring
条条大路通向memcpy
.
要凭经验验证这些说法,您可以使用 stdlib 内存分析工具 tracemalloc
:
# s.py
import tracemalloc
tracemalloc.start()
before = tracemalloc.take_snapshot()
a = "." * 7 * 1024**2 # 7 MB of ..... # line 6, first alloc
b = a[1:] # line 7, second alloc
after = tracemalloc.take_snapshot()
for stat in after.compare_to(before, 'lineno')[:2]:
print(stat)
您应该会看到前两个统计信息输出,如下所示:/tmp/s.py:6: size=7168 KiB (+7168 KiB), count=1 (+1), average=7168 KiB
/tmp/s.py:7: size=7168 KiB (+7168 KiB), count=1 (+1), average=7168 KiB
这个结果显示了两个 7 meg 的分配,内存复制的有力证据,并且将指示这些分配的确切行号。尝试从
b = a[1:]
更改切片进入 b = a[0:]
查看整个字符串特殊情况的效果:现在应该只有一个大分配,并且 sys.getrefcount(a)
将增加一。理论上,由于字符串是不可变的,因此实现可以为子字符串切片重用内存。这可能会使任何基于引用计数的垃圾收集过程复杂化,因此在实践中它可能不是一个有用的想法。考虑从更大的字符串中取出一小部分的情况 - 除非您对切片实现某种子引用计数,否则在子字符串的生命周期结束之前无法释放更大字符串的内存。
对于特别需要可以在不复制底层数据的情况下进行切片的标准类型的用户,有
memoryview
.见 What exactly is the point of memoryview in Python有关更多信息。
关于python - 字符串切片是否在内存中执行复制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64871329/