CPython-对象/类型系统
Python中一切皆对象,包括实例对象和类型对象,如整数、浮点数、字符串是实例对象,整数类型、浮点数类型、字符串类型是类型对象。
# [Python]
>>> n=10
>>> type(n)
<type 'int'>
>>> type(int)
<type 'type'>
>>> sys.getsizeof(n)
20
>>> sys.getsizeof(int)
444
>>>
如演示代码所示,整数对象(n)的类型是int(整数类型),整数类型对象的类型是type(类型对象);其中整数对象占用20字节内存,而整数类型对象占用444字节内存[这些数值取决于测试所使用的设备和系统]。
看到占用内存的数值大小,一定会非常好奇这些内存用来做什么,后面会贴源码来进行说明。对象是数据以及基于这些数据的操作的集合,在Python中对象一旦被创建,其在内存中的大小就固定不变。
PyObject
PyObject是对象系统的核心,所有的对象都包含这部分数据。它主要包括:用于内存管理的引用计数(ob_refcnt)、类型对象指针(ob_type)、堆内存中对象管理用的双向链表指针(_ob_next, _ob_prev)[总共16字节]。
其中ob_type指向对象所属的类型对象,而类型对象是有定义操作集合的,所以在运行时通过ob_type找到合适的操作(函数调用),实现了Python的动态机制。
// [C]
typedef struct _object {
struct _object *_ob_next;
struct _object *_ob_prev;
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
PyVarObject
同一类型的对象占用的内存大小并非相同的,如字符串对象,依据字符串长度占用的内存大小不同,所以这种变长对象用PyVarObject结构体来表示。当然也有一些类型对象是定长的,如整数对象、浮点数对象。
// [C]
typedef struct {
PyObject_HEAD // PyObject数据部分
Py_ssize_t ob_size; // 大小
} PyVarObject;
相对于PyObject,定长对象只增加了变长对象的大小字段(ob_size)。
PyObject和PyVarObject的数据中,都有指向类型对象的指针,类型对象是_typeobject结构体,即PyTypeObject。
PyTypeObject
类型对象也包含实例对象的数据部分(引用计数、类型对象指针,对象双链表指针),它包含的更多字段是适用于此类型的操作。比如:
标准操作:释放内存(tp_dealloc)、打印(tp_print)、获取属性(tp_getattr)、设置属性(tp_setattr)、比较(tp_compare)。
数值对象操作集合(tp_as_number)、序列对象操作集合(tp_as_sequence)、关联对象操作集合(tp_as_mapping)等[限于篇幅省略了很多字段]。
// [C]
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; // 类型名
Py_ssize_t tp_basicsize, tp_itemsize; // 内存分配 // 标准操作
destructor tp_dealloc;
printfunc tp_print;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
cmpfunc tp_compare;
reprfunc tp_repr; PyNumberMethods *tp_as_number; // 数值对象应该支持的操作
PySequenceMethods *tp_as_sequence; // 序列对象应该支持的操作
PyMappingMethods *tp_as_mapping; // 关联对象应该支持的操作 ...
} PyTypeObject;
注:像cmpfunc是定义的函数指针,其它的函数指针也有类似的定义。
typedef int (*cmpfunc)(PyObject *, PyObject *); // 比较两个PyObject对象的函数指针
在Python中,一般来说对象是不能被静态初始化的也不能在栈空间生存。但内建的类型对象都是被静态初始化的,如PyInt_Type、PyFloat_Type、PyString_Type等,其中PyInt_Type的初始化代码如下:
// [C]
PyTypeObject PyInt_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) // ob_type == &PyType_Type
"int",
sizeof(PyIntObject),
0,
(destructor)int_dealloc, /* tp_dealloc */
(printfunc)int_print, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)int_compare, /* tp_compare */
(reprfunc)int_to_decimal_string, /* tp_repr */
&int_as_number, /* tp_as_number */
...
};
注:PyType_Type是类型的类型。
说完了内建类型,那自定义类型在Python是如何表示的呢?
自定义class演示代码如下:
# [Python]
>>> class A(object):
... def __init__(self):
... pass
...
>>> A.__class__
<type 'type'>
>>> type.__class__
<type 'type'>
可以看到自定义class的类型对象是PyType_Type,即用PyType_Type对象来创建自定义类型对象。
PyType_Type的初始化代码如下:
// [C]
PyTypeObject PyType_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) // ob_type == &PyType_Type
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
(destructor)type_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)type_repr, /* tp_repr */
0, /* tp_as_number */
...
};
自此把实例对象、类型对象基本讲清楚了,至于具体类型的特性、操作则需要后续再具体讲解。
CPython-对象/类型系统的更多相关文章
- javascript中15种原生对象类型系统综述
前面的话 在编程语言中,能够表示并操作的值的类型称做数据类型,编程语言最基本的特性就是能够支持多种数据类型.javascript拥有强大的类型系统,主要包括原生对象.宿主对象和浏览器拓展对象,本文主要 ...
- 基于类型系统的面向对象编程语言Go
(整理自网络) 面向对象编程 Go语言的面向对象编程(OOP)非常简洁而优雅.说它简洁,在于它没有了OOP中很多概念,比如:继承.虚函数.构造函数和析构函数.隐藏的this指针等等.说它优雅,是它的面 ...
- javascript中的null,对象系统还是非对象系统?
1.一直以来的认知 在我学习js的过程中,爱民老师的绿皮书里将js的类型系统分成了两类: 其一是元类型系统:由typeof运算来检测 其二是对象类型系统:是元类型的object的一个分支 而null这 ...
- 采访ServiceStack的项目领导Demis Bellot——第1部分(网摘)
ServiceStack是一个开源的.支持.NET与Mono平台的REST Web Services框架.InfoQ有幸与Demis Bellot深入地讨论了这个项目.在这篇两部分报道的第1部分中,我 ...
- js:语言精髓笔记12--动态语言特性(2)
对于括号内: 通过赋值时发生的重写: (Object1 = function() {}).prototype.value = 100; var obj1 = new Object1; console. ...
- 采访ServiceStack的项目领导Demis Bellot——第1部分(转)
ServiceStack是一个开源的.支持.NET与Mono平台的REST Web Services框架.InfoQ有幸与Demis Bellot深入地讨论了这个项目.在这篇两部分报道的第1部分中,我 ...
- JS数据类型的理解(猜测)
Js 数据类型 对于这个主题,首先来看几个问题,如果你对这几个问题很清楚的话,那就请直接跳过吧,不用接着往下看了,如果不清楚,建议你还是看看. 1)如果判断函数?function 和object的联系 ...
- Qt经典—线程、事件与Qobject(耳目一新)
介绍 You’re doing it wrong. — Bradley T. Hughes 线程是qt channel里最流行的讨论话题之一.许多人加入了讨论并询问如何解决他们在运行跨线程编程时所遇到 ...
- 【转】Qt事件循环与线程 二
转自:http://blog.csdn.net/changsheng230/article/details/6153449 续上文:http://blog.csdn.net/changsheng230 ...
- Python源码剖析之准备工作
一个Python程序开发者, 也是C语言爱好者, 为了加强自己对Python语言实现的理解, 最近选择阅读下陈儒老师的书, 对Python3.5.1源码进行阅读, 再次记录下读书笔记. 一.Pyth ...
随机推荐
- 最新 uni-app 免费教程
最新 uni-app 免费教程 uni-app 快速入门 steps 建议第一步,看完uni-app官网的首页介绍. 建议第二步,通过快速上手,亲身体验下uni-app. 建议第三步,看完<un ...
- nodemon all in one
nodemon all in one https://nodemon.io/ https://github.com/remy/nodemon#nodemon https://www.npmjs.com ...
- Python Coding Interview
Python Coding Interview Python Advanced Use enumerate() to iterate over both indices and values Debu ...
- jest & code testing
jest jest & code testing https://jestjs.io/zh-Hans/ 24.9 https://jestjs.io/docs/zh-Hans/getting- ...
- Web 安全 & 反爬虫原理
Web 安全 & 反爬虫原理 数据加密/解密 HTTPS ip 封锁 请求限制 爬虫识别,canvas 指纹 refs https://segmentfault.com/a/119000001 ...
- axios upload excel file
axios upload excel file https://github.com/axios/axios/issues/1660 https://stackoverflow.com/questio ...
- 在多线程编程中不要使用sleep()、usleep()函数
这两个函数是非线程安全的,可能会造成程序卡死. 对于c++程序,建议使用std::this_thread::sleep_for()和std::this_thread::yield()代替. 纯c程序可 ...
- 数据序列化工具——flatbuffer
flatbuffer是一款类似于protobuf的数据序列化工具.所有数据序列化,简单来说,就是将某程数据结构按照一定的格式进行编码与解码,以方便在不同的进程间传递后,能够正确的还原成之前的数据结构. ...
- [转]Linux 线程实现机制分析 Linux 线程实现机制分析 Linux 线程模型的比较:LinuxThreads 和 NPTL
转载地址:https://www.cnblogs.com/MYSQLZOUQI/p/4233630.html 自从多线程编程的概念出现在 Linux 中以来,Linux 多线应用的发展总是与两个问题脱 ...
- [转]ROS Q&A | How to read LaserScan data
http://www.theconstructsim.com/read-laserscan-data/ Step 1. Open a project on ROS Development Studio ...