Python 3中for循环内存分配疑问:排序对象存储位置解析
Python中for循环内sorted返回对象的内存存储问题
问题场景
有两种使用sorted()的for循环写法:
第一种写法:
ls = [2, 1, 4, 6, 7] for i in sorted(ls): print(i)
第二种写法:
ls = [2, 1, 4, 6, 7] reverse = sorted(ls) for i in reverse: print(i)
将第一种写法放入可视化工具时,发现排序后的列表对象未被显示,但sorted()确实会返回新的列表对象。已知for循环底层会调用可迭代对象的iter()方法,迭代器必须从排序后的列表获取数据,因此这个对象肯定存在于内存中,疑惑它的存储位置及为何未被可视化工具显示。
解答
临时对象的内存存在性
第一种写法中,sorted(ls)返回的排序后列表确实存在于堆内存中,只是它没有被绑定到一个用户定义的具名变量(比如第二种写法里的reverse),所以常规的可视化工具不会主动展示这类临时对象。内存管理逻辑
- 调用
sorted(ls)时,Python会在堆内存中创建新的排序后列表对象,将该对象的引用直接传递给for循环的迭代机制。 - for循环会调用这个临时对象的
__iter__()方法生成迭代器,迭代过程中迭代器会一直持有该对象的引用,因此对象的引用计数大于0,不会被垃圾回收。 - 当循环结束后,迭代器被销毁,临时对象的引用计数降为0,Python的垃圾回收机制会在合适的时机回收该对象占用的内存。
两种写法的核心差异
第二种写法里,reverse = sorted(ls)将新列表绑定到了变量reverse上,只要reverse变量未被销毁(引用计数不为0),对应的列表对象就会持续存在,可视化工具也能通过变量名追踪并展示这个对象。而第一种写法的临时对象没有显式的变量绑定,可视化工具通常只展示有明确名称的对象,不会追踪所有临时创建的匿名对象。验证临时对象存在的方法
可以通过Python的内置工具验证临时对象的存在,比如使用sys.getrefcount()查看引用计数,或者通过迭代器的__self__属性访问原对象:
import sys ls = [2, 1, 4, 6, 7] # 获取临时列表的迭代器 iter_obj = iter(sorted(ls)) # 查看迭代器对应的原对象的引用计数(调用getrefcount会额外增加一次引用) print(sys.getrefcount(iter_obj.__self__)) # 执行迭代 for i in iter_obj: print(i) # 循环结束后再次查看引用计数,会发现数值下降 print(sys.getrefcount(iter_obj.__self__))
内容的提问来源于stack exchange,提问作者Kabalchik
相关产品推荐
相关产品推荐

