『Python』源码解析_从ctype模块理解底层源码

一、对象的存储结构

对象的引用计数

从c代码分析可知,python所有对象的内存有着同样的起始结构:引用计数+类型信息,实际上这些信息在python本体重也是可以透过包来一窥一二的,

from ctypes import *

class PyObject(Structure):
    _fields_ = [("refcnt", c_size_t),
                ("typeid", c_void_p)]

a = "this is a string"

# 通过id(a)可以获得对象a的内存地址,而PyObject.from_address()可以将
# 指定的内存地址的内容转换为一个PyObject对象。通过此PyObject对象obj_a
# 可以访问对象a的结构体中的内容。
obj_a = PyObject.from_address(id(a))
print(obj_a.refcnt)
b = [a]*10
print(obj_a.refcnt)

查看对象a的引用次数,原文中返回值1,实际返回2,可能是python3相对2的改动使得多引用一次,接下来创建一个列表,此列表中的每个元素都是对象a,因此此列表应用了它10次,所以引用次数变为了12。

对象的类型

查看对象a的类型对象的地址,它和id(type(a))相同,而由于对象a的类型为str,因此也就是id(str),

print(obj_a.typeid)
print(id(type(a)))
print(id(str))

1825992064

1825992064

1825992064

验证一下,从这个地址读取python对象试试,

obj_s = PyObject.from_address(id(str))
print(obj_s.typeid)

1825980464

指向新的地址,如果这个地址对应python的类型对象,那么它的类型应该是元类对象,我们尝试一下在源码解析一书上的知识。

元类的特殊性质

print(id(type))
type_obj = PyObject.from_address(id(type))
print(type_obj.typeid)

1825980464

1825980464

符合,str(对应字符串类)的类型、元类本身的类型的、元类本身,三者的地址都指向同一位置。

猜你喜欢

转载自www.cnblogs.com/hellcat/p/8948159.html