Python 缓存了哪些基本对象

问题描述

众所周知,Python(或至少是 cpython)会缓存一些第一个整数。即,以下成立

a = 1
b = 1
print(a is b)  # True 

同时也

a = 1000
b = 1000
print(a is b)  # False

更广泛地说,我们可以使用下面列出的方法来查看缓存了哪些基本对象(或者“是单例对象”,如果您愿意的话)。

def does_survive_pickling(obj):
    after_pickling = pkl.loads(pkl.dumps(obj))
    return obj is after_pickling

我的问题是

  • 表现出这种行为的对象是什么? (比如说,“幸存”了酸洗方法

    • 在我的 cpython 3.9.1 中,它们至少是 [-5,256] 中的整数(相应字符也是如此,即 8 位 ACII)、()NoneTrueFalseEllipsis。还有其他的吗?
  • 这些对象的数量和种类取决于什么条件?

    • 我认为 Python 实现非常重要。

    • 还有什么(比如说,对于 cpython)?版本?硬件(例如 32 位与 64 位处理器)?还有别的吗?

  • 是否可以在某处找到这些信息? (在文档中?)

我会很高兴收到任何评论、答案或有用的链接。谢谢!

也许 cpython 的行为是唯一对我来说真正重要的行为。不过,出于好奇,欢迎提供有关 PyPy 和其他信息的信息。


作为背景,我正在开发一个需要管理其内存资源的库。因此,我努力学习更多关于 Python 内存管理的知识。在这种情况下,我对 pickled-unpickled 对象(更普遍的是序列化-反序列化)的内存占用感兴趣。

比如说,你从一堆内部结构相互交织的对象开始。如果将这些对象中的每一个都保存到磁盘并再次加载,会发生什么情况(内存消耗增加了多少)?

如果是一些1s的嵌套列表,与1000s的同一个列表差别很大。

解决方法

依赖实施细节是未来灾难的秘诀......

对象缓存是一个实现细节,实际缓存的对象可能会在任何新 Python 版本中更改,而不会发出任何警告。

如果你有很多大的只读对象,其中大部分都是equals,那么你应该考虑在pickle模块级别实现特殊处理,比如特殊的__reduce__方法,pair __getstate____setstate__,或使用带外数据处理。不幸的是,很难知道什么是您实际用例的最佳方式。我的观点是,您应该深入研究 pickle 模块文档,以找出是否可以使用记录的方式来节省内存。