slots - Python的结构体 转
简单的说,slots提供了一种强制声明对象属性的方法。如果在类定义的时候定义了__slots__的值(string列表),这个类的对象就只能使用列表中属性名。
class A(object):
def __init__(self):
self.uuid = 2
self.word = ‘hello'
变成:
class B(object):
__slots__ = ( 'value', ‘other')
def __init__(self):
self.uuid = 2
self.word = ‘hello'
self.other = ‘world' # AttributeError: ‘B’ object has no attribute ‘other’
是不是很像C的结构体?注意__slots__只是起了限定的作用,属性还是要先赋值才读取。
引入slots的主要目的是节省内存。默认python会为每个对象创建一个dict,通过__dict__索引。脚本中定义的属性其实都存在这个dict中。如果类定义了__slots__,创建对象时就不会创建dict,这也就解释了为什么不能随意增加属性了。
能省多少内存呢?dict对象本身只有248bytes。而dict的容量通常是其中有效entry的2~4倍,使用slots不会减少有效entry的数量,因此大概能省一半的空entry。原文中能从25G内存中省下9G,应该是不仅对象很多,而且每个对象的属性很多。考虑到我们实际的应用环境,似乎达不到这样的量。而且服务端很多类都是在C中定义的,其实效果是一样的。
性能上会有提高吗?实测结果几乎没有,从实现上可以看出,其实还是需要做一次dict查找。
目前想到的一个用处是提高可维护性:虽然作为动态语言,允许随意增删对象的属性是个很方便的设定。但是也会对可维护性造成一定的影响。比如一不小心写错属性名。如果是赋值,python会默默的以为是一个新的,导致真正要改的数据没改到,如果是读取,一直到运行时跑到这段代码才会报错。通过定义slots,可以一定程度上避免错误赋值,但是对于错误读取就作用不大了。
关于slots的使用有一些规则和限制,在python自带的文档里有详细说明。
最后是实现的一些细节。代码主要在Objects/typeobject.c。下面两张图是普通类和使用slots的类的区别(红色部分)。

对于普通类A,我们可以看到,它的tp_dictoffset的值是一个偏移量,对应于这个类所创建的对象(比如a)内存中的从头部数到这个偏移量的内存地址,其实是一个PyObject指针。这个指针指向一个dict对象,也就是我们在运行期可以访问到的a.__dict__。脚本中定义的所有属性就保存在这个dict当中。由于这两个指针分别有8字节,因此整个对象a的大小是基本大小16加上8*2,总共32字节。

而对于使用了slots的类B,它的tp_dictoffset就变成了0。换句话说就是没有分配dict对象。那怎么索引到属性呢?其实是上升到了类的层次。在Python中,所有东西都是对象,包括类型本身也是对象,类型对象的类型是PyType_Type(脚本中的type)。听起来很绕,其实这里只是想说明,类型对象是变长对象,包括基本信息加上若干PyMemberDef对象。每个PyMemberDef对象其实就对应于slots中个每个属性声明。而这个类所创建的对象中,也会为每个属性声明分配一个PyObject指针的内存。在初始化类型的时候(PyType_Ready函数),系统会为每个PyMemberDef创建一个descriptor,并在类的__dict__(不是对象的__dict__,从类的tp_dict指向)中建立从属性名到descriptor的映射。
因此,无论哪种方法,都需要进行一次hash查找,区别只是在类的__dict__还是对象的__dict__中。
最后的最后,推荐一下这个不需要安装的在线画图工具:lucidchart
slots - Python的结构体 转的更多相关文章
- python 传递结构体指针到 c++ dll
CMakeLists.txt # project(工程名) project(xxx) # add_library(链接库名称 SHARED 链接库代码) add_library(xxx SHARED ...
- python 实现结构体
# python 使用类创建结构体 class Myclass(object): class Struct(object): def __init__(self, name, age, job): s ...
- c++调用python系列(1): 结构体作为入参及返回结构体
最近在打算用python作测试用例以便对游戏服务器进行功能测试以及压力测试; 因为服务器是用c++写的,采用的TCP协议,当前的架构是打算用python构造结构体,传送给c++层进行socket发送给 ...
- Python与C++结构体交互
需求:根据接口规范,实现与服务端的数据交互 服务端结构体分包头.包体.包尾 包头C++结构体示例如下 typedef struct head { BYTE string1; BYTE string2; ...
- ctypes 操作 python 与 c++ dll 互传结构体指针
CMakeLists.txt # project(工程名) project(blog-3123958139-1) # add_library(链接库名称 SHARED 链接库代码) add_libra ...
- python如何将指定路径下的某类型文件,返回一个树形结构体,让前端显示为树形的目录结构
最近遇到一个问题就是某个linux的目录下有各种文件现在的要求是只需要返回.kml格式的文件,并根据前端要求返回如下结构体即:[{'children': [{'children': [{'title' ...
- 『Python CoolBook』C扩展库_其四_结构体操作与Capsule
点击进入项目 一.Python生成C语言结构体 C语言中的结构体传给Python时会被封装为胶囊(Capsule), 我们想要一个如下结构体进行运算,则需要Python传入x.y两个浮点数, type ...
- Python 定义及使用结构体
Python中没有专门定义结构体的方法,但可以使用class标记定义类来代替结构体,其成员可以在构造函数__init__中定义,具体方法如下. class seqNode: def __init__( ...
- python调用c/c++时传递结构体参数
背景:使用python调用linux的动态库SO文件,并调用里边的c函数,向里边传递结构体参数.直接上代码 //test1.c # include <stdio.h> # include ...
随机推荐
- history命令
在 Linux 下面可以使用 history 命令查看用户的所有历史操作,同时 shell 命令操作记录默认保存在用户目录的 .bash_history 文件中.通过这个文件可以查询 shell 命令 ...
- linux常用命令之--磁盘管理命令
linux的磁盘管理命令 1.查看磁盘空间 df:用于显示磁盘空间的使用情况 其命令格式如下: df [-option] 常用参数: -i:使用inodes显示结果 -k:使用KBytes显示结果 - ...
- Python 代码性能优化技巧
选择了脚本语言就要忍受其速度,这句话在某种程度上说明了 python 作为脚本的一个不足之处,那就是执行效率和性能不够理想,特别是在 performance 较差的机器上,因此有必要进行一定的代码优化 ...
- 多校6 1001 HDU5793 A Boring Question (推公式 等比数列求和)
题解:http://bestcoder.hdu.edu.cn/blog/ 多校6 HDU5793 A Boring Question // #pragma comment(linker, " ...
- matlab中图像处理常见用法
一. 读写图像文件 1. imread imread函数用于读入各种图像文件,如:a=imread('e:/w01.tif') 注:计算机E盘上要有w01相应的.tif文件. 2. imwrite i ...
- Install_pygments
安装Pygments语法高亮 On OS X Leopard, Snow Leopard 1 $ sudo easy_install Pygments Alternatively on OS X wi ...
- 《Genesis-3D开源游戏引擎完整实例教程-2D射击游戏篇:简介及目录》(附上完整工程文件)
G-3D引擎2D射击类游戏制作教程 游戏类型: 打飞机游戏属于射击类游戏中的一种,可以划分为卷轴射击类游戏. 视觉表现类型为:2D 框架简介: Genesis-3D引擎不仅为开发者提供一个3D游戏制作 ...
- 关于python的import
在软件包里,必须添加__init__.py文件. 想要对外公开的module必须在__init__.py内import一次,这样这些module才能被外部代码import并调用.
- asp.net mvc 实体类成员变量标识示例
检查不能为空 [Required] public string ID { get; set; } 检查最大长度 [StringLength(36, ErrorMessage = "长度不可超 ...
- 最全面的 MySQL 索引详解
什么是索引? 1.索引 索引是表的目录,在查找内容之前可以先在目录中查找索引位置,以此快速定位查询数据.对于索引,会保存在额外的文件中. 2.索引,是数据库中专门用于帮助用户快速查询数据的一种数据结构 ...