sat*_*oru 7 python object python-internals
说我有一个A类:
class A(object):
def __init__(self, x):
self.x = x
def __str__(self):
return self.x
Run Code Online (Sandbox Code Playgroud)
我sys.getsizeof用来查看需要多少字节的实例A:
>>> sys.getsizeof(A(1))
64
>>> sys.getsizeof(A('a'))
64
>>> sys.getsizeof(A('aaa'))
64
Run Code Online (Sandbox Code Playgroud)
如上面的实验所示,A无论是什么,物体的大小都是相同的self.x.
所以我想知道python如何在内部存储一个对象?
Tho*_*ers 23
这取决于什么样的对象,以及哪个Python实现:-)
在CPython中,这是大多数人在使用时使用的python,所有Python对象都由C结构表示PyObject."存储对象"的所有内容确实存储了一个PyObject *.该PyObject结构保持最低限度的信息:对象的类型(一个指针到另一个PyObject)和其引用计数(一个ssize_t在C中定义的类型延伸,以与额外的信息这个结构,他们需要在对象本身存储,有时分配尺度的整数.)额外的数据.
例如,元组(实现为PyTupleObject"扩展"PyObject结构)存储它们的长度以及PyObject它们包含在结构本身内的指针(结构在定义中包含1长度数组,但实现分配了一块内存.正确的大小来保存PyTupleObject结构加上与元组应该保持的项目完全相同的数量.)同样,strings(PyStringObject)存储它们的长度,它们的缓存哈希值,一些字符串缓存("实习")簿记,以及实际的char*他们的数据.因此,元组和字符串是单个内存块.
另一方面,lists(PyListObject)存储它们的长度,a存储它们PyObject **的数据,另一个存储它们ssize_t以跟踪它们为数据分配了多少空间.因为Python PyObject在任何地方存储指针,所以一旦分配了PyObject结构就无法生成它 - 这样做可能需要移动结构,这意味着找到所有指针并更新它们.因为列表可能需要增长,所以它必须与PyObject结构分开分配数据.元组和字符串不能增长,因此它们不需要这样.Dicts(PyDictObject)以相同的方式工作,尽管它们存储密钥的值,值和缓存的哈希值,而不仅仅是项目.Dict还有一些额外的开销来容纳小的dicts和专门的查找功能.
但是这些都是C中的类型,你通常可以通过查看C源来查看它们将使用多少内存.用Python而不是C 定义的类实例并不那么容易.最简单的情况下,经典的类的实例,不是那么困难:它是一个PyObject存储了PyObject *其类(这是不一样的东西存储在类型PyObject结构的话),一个PyObject *它的__dict__属性(它包含所有其他的实例属性)和a PyObject *weakreflist(由weakref模块使用,只在必要时才初始化.)实例的__dict__实例通常是唯一的,因此在计算此类实例的"内存大小"时,您通常也要计算属性dict的大小.但它不必具体针对实例!__dict__可以分配到很好.
新式课程复杂化.与经典类不同,新样式类的实例不是单独的C类型,因此它们不需要单独存储对象的类.他们也有余地__dict__和weakreflist参考,但不同于经典的情况下,他们并不需要的__dict__任意属性的属性.如果类(及其所有基类)用于__slots__定义严格的属性集,并且没有命名这些属性__dict__,则实例不允许任意属性,也不分配dict.另一方面,定义的属性__slots__必须存储在某处.这是通过存储来完成的PyObject直接在PyObject结构中指向这些属性值的指针,就像使用C语言编写的类型一样.无论属性是否设置,每个条目都__slots__将占用a PyObject *.
所有这一切,问题仍然存在,因为Python中的所有东西都是一个对象,而拥有一个对象的所有内容都只是一个引用,有时很难在对象之间绘制线条.两个对象可以引用相同的数据位.他们可能只拥有该数据的两个引用.摆脱两个对象也摆脱了数据.他们都拥有这些数据吗?只有其中一个,但如果是这样,哪一个?或者你会说他们拥有一半的数据,即使摆脱一个对象不会释放一半的数据?Weakrefs可以使这更加复杂:两个对象可以引用相同的数据,但删除其中一个对象可能会导致另一个对象也摆脱对该数据的引用,导致数据被清除.
幸运的是,常见的情况很容易弄明白.有一些用于Python的内存调试器可以很好地跟踪这些事情,比如heapy.只要您的类(及其基类)相当简单,您就可以对有多少内存进行有根据的猜测 - 特别是在大量情况下.如果您真的想知道数据结构的确切大小,请咨询CPython源代码; 大多数内置类型都是在中描述Include/<type>object.h和实现的简单结构Objects/<type>object.c.PyObject结构本身在中描述Include/object.h.请记住:它一直指向下方; 那些也占用了房间.
| 归档时间: |
|
| 查看次数: |
5086 次 |
| 最近记录: |