python 对象

在python中,对象就是为C中的结构体在堆上申请的一块内存,一般来说,对象是不能被静态初始化的,并且不能再栈空间上生存。本文主要对Python的基本数据类型做简单的介绍。

PyObject

在python中,所有东西都是对象,而所欲的对象都拥有一些共性(object.h/PyObject)。
PyObject是整个python对象机制的核心。

typedef struct _object {
    PyObject_HEAD
} PyObject;

在release模式下编译python时,PyObject如下:

typedef struct _object {
    int ob_refcnt; //引用计数
    struct _typeobject *ob_type; //类型
} PyObject;

其中,ob_refcnt为int整型,实现了基于引用计数的垃圾收集机制。对于某一对象A,当有一个新的PyObject引用该对象时,A的引用计数应该增加;而当这个PyObject被删除时,A的引用计数应该减少;当A的引用计数减少到0时,A就可以从堆上被删除,以释放出内存供别的对象使用。

引用计数

PyObject中的ob_refcnt是一个32位的整形变量,这实际蕴含着Python所有的一个假设,既对一个对象的引用不会超过一个整形变量的最大值。

整数对象

小整数对象

在python中,所有对象都存活在堆上,python重复地使用malloc申请空间,大大降低了运行效率,造成大量内存碎片,影响整体性能。因此,在python中,对小整数对象使用了对象池技术,用来缓存所有的小整形对象(对重复的对象不需要重复的malloc)。

NSMALLPOSINTS和NSMALLNEGINTS来修改小整数对象池的范围(默认分别为257和-5)。

大整数对象

对于小整数,使用对象池技术完全缓存其PyIntObject对象,而对于其他整数,python提供了一种PyIntBlock结构供大整形对象使用。PyIntBlock是通过维护一块内存(Block)来供大整数使用,并通过单向列表block_list来维护。

Python的设计者为了提高代码执行效率放弃了类型安全使用了宏来代替函数。

当一个PyIntObject对象被销毁时,它所占用的内存并不会被释放,而是继续被python保留着,加入到free_list所维护的自有内存链表,为其他需要创建对象的内存使用。

字符串对象

在python中,PyStringObject是字符串对象的实现,它是一个拥有可变长度内存的对象。

trpdef struct {
    PyObject_VAR_HEAD //ob_size字符串长度
    long ob_shash; //字符串hash值
    int ob_sstate;
    char ob_sval[1];
} PyStringObject;

在PyStringObject中,还使用了intern机制和缓存池技术。

intern机制和缓存池

intern机制的目的:保证被intern之后的字符串在python整个运行期间只对应唯一的一个PyStringObject对象。

intern机制的关键是在系统中有一个(key,value)映射的集合,记录所有被intern机制处理过的PyStringObject对象。当python在创建一个字符串时,会首先在interned中检查是否已经有该字符串对应的PyStringObject对象了,如果有,则不用创建新的,这样可以节省内存空间。其实,Python始终会为字符串创建PyStringObject对象,intern机制是在创建之后才会生效的,通常python在运行时创建一个PyStrhingObject对象temp后,基本就会销毁该对象(引用计数减1)。

类似小整形的缓存池,python为PyStringObject中的一个字节的字符对应的PyStringObject对象设计对象池characters。

Python中的处理顺序:

  • 判断是否为一个字符
  • 创建PyStringObject对象进行intern操作
  • 将intern结果缓存到字符缓冲池中

PyStringObject效率问题

在Python中"+"操作符进行字符串连接的方法效率极其低下,其根源在于python中的PyStringObject对象是一个不可变对象。这就意味着当进行字符串连接时,实际上必须要创建一个新的PyStringObject对象。因此,如果需要连接N个PyStringObject对象,就必须进行N-1次内存申请及内存搬运工作,严重影响python的执行效率。

官方推荐利用PyStringObject对象的join操作来对存储在list和tuple中一组PyStringObject对象进行连接操作,只需要分配一次内存,执行效率大大提高。

join操作会统计出list中所有PyStringObject对象的字符串长度,然后申请内存。

列表对象

PyListObject是Python提供的对列表的抽象。它类似于C++中的vector,而不是list。

typedef struct {
    PyObject_VAR_HEAD
    PyObject **ob_item; //元素首地址
    int allocated; //实际申请内存的个数(部分没有被使用,类似于vector)
} PyListObject;

其中,ob_item为指向元素列表的指针。

python所采用的内存管理策略和c++中vector采取的内存管理策略一样,并不是寸多少数据就要申请对应大小的空间,这样内存管理的效率较低,因此,在每一次申请内存时PyListObject总会申请一大块内存,该内存的大小就记录在allocated中,而实际被使用的内存数量记录在ob_size中。

对象缓存池

在创建一个新的list时,首先创建PyListObject对象,然后创建PyListObject对象所维护的元素列表;在销毁一个List时,首先销毁PyListObject所维护的列表,然后释放掉PyListObject本身,但是在释放之前python会检查缓冲池free_lists,查看其中缓存的PyListObject的数量是佛已经满了,如果没有,就将该数据对象加入到穿存池中,否则删除。

Dict对象

与map不同,PyDictObject采用散列表(hash table)。在最优情况下,散列表能提供O(1)复杂度的搜索效率。

散列表

散列表的基本思想是通过一个函数将需搜索的键值映射为一个整数,将这个整数视为索引值访问某片连续性的内存区域。

在使用散列表的过程中,不同的对象经过散列函数的作用,可能被映射为相同的散列值。随着需要存储的数据的增多,这样的冲突就会发生得越来越频繁。散列冲突是散列表不可避免的问题,当散列表的装载率(已使用空间和总空间的比值)大于2/3时,散列冲突发生的概率就会大大增加。

在STL库的hash table采用开链法来解决冲突,而python中采用开放地址法。当产生冲突时,python会通过一个二次探测函数f计算下一个候选位置,如果该候选位置可用,则可将待插入元素放到该位置,否则再次调用探测函数f,寻找可用位置。

关联容器entry

typedef struct {
    Py_ssize me_hash; //散列值
    PyObject *me_key;
    PyObject *me_value;
}

在PyDictObject对象生存变化的过程中,其中entry会在不同的状态间转换:Unused、Active和Dummy。

  • Unused:当一个entry的me_key和me_value都是NULL;
  • Active:当entry中存储了一个(key,value)对时;
  • dummy:当entry中存储的(key,value)被删除后,entry的状态不能直接从Active转到unused(伪删除),否则会出现冲突探测链中断。


本文 由 cococo点点 创作,采用 知识共享 署名-非商业性使用-相同方式共享 3.0 中国大陆 许可协议进行许可。欢迎转载,请注明出处:
转载自:cococo点点 http://www.cnblogs.com/coder2012

时间: 2024-10-30 15:02:46

python 对象的相关文章

Python对象认知(1)

       Python 是一种面向对象的解释型计算机程序设计语言.那讲到类我们肯定要说一下对象,以及类和对象之间的关系. 类是用来规范和描述实体对象的.类包含(定义)一系列的属性和方法.那对象又是什么呢?对象就是由属性和方法组成,对象是类的实例化,对象是类的具体表现,所以对象含有类属性的具体值.那说到这里感觉还是一头雾水啊,那我们来举一个栗子吧. 在Python中,一切万物皆对象,比如眼前的这只狗---泰迪,在Python世界里他就是一个对象,他有一些特征,比如大小,颜色,爱啪啪等.其实这就

Python回顾与整理2:Python对象

0.说明                  说对象是面向对象编程语言最重要的一部分一点也不为过,没有了"对象",面向对象将无从谈起.Python也是如此,如果无法掌握对象,你很难有大的进步与提升. 1.Python对象 (1)对象特性         Python使用对象模型来存储数据,构造任何类型的值都是一个对象,所有的Python对象都拥有下面的三个特性: 身份:每个对象一唯一身份标识,可使用内建函数id()查看该值(可以认为这个值是该对象的内在地址) 类型:对象的类型决定了对象(

Python 自省指南 如何监视您的 Python 对象

简介: 自省揭示了关于程序对象的有用信息.Python 是动态的面向对象的编程语言,提供了很棒的自省支持.本文展示了该语言的许多能力,从最基本形式的帮助到较为高级形式的调查. 什么是自省? 在日常生活中,自省(introspection)是一种自我检查行为.自省是指对某人自身思想.情绪.动机和行为的检查.伟大的哲学家苏格拉底将生命中的大部分时间用于自我检查,并鼓励他的雅典朋友们也这样做.他甚至对自己作出了这样的要求:"未经自省的生命不值得存在."(请参阅 参考资料以获取关于苏格拉底更多

python对象及面向对象技术详解_python

本文实例讲述了python对象及面向对象技术.分享给大家供大家参考,具体如下: 1 先看一个例子. 本章将讲解这个例子程序: 文件: fileinfo.py: """Framework for getting filetype-specific metadata. Instantiate appropriate class with filename. Returned object acts like a dictionary, with key-value pairs f

浅谈Python 对象内存占用_python

一切皆是对象 在 Python 一切皆是对象,包括所有类型的常量与变量,整型,布尔型,甚至函数. 参见stackoverflow上的一个问题 Is everything an object in python like ruby 代码中即可以验证: # everythin in python is object def fuction(): return print isinstance(True, object) print isinstance(0, object) print isinst

Python对象体系深入分析_python

本文较为详细的分析了了Python的对象体系.分享给大家供大家参考.具体如下: Guido用C语言创造了Python,在Python的世界中一切皆为对象. 一.C视角中的Python对象 让我们一起追溯到源头,Python由C语言实现,且向外提供了C的API http://docs.python.org/c-api/index.html . 我们思考问题的时候,可能对于对象这种东西很容易理解,而计算机能理解的只有0,1序列这样的字节序列,从根本上讲,我们所说的计算机语言中的对象只是在内存中的一块

[笔记]Python对象基础

以前写在Evernote上的笔记. Python对象机制最基础的是PyObject和PyVarObject,而后者又仅仅是比前者多了一个变量而已. 在object.h中有这两者的定义: typedef struct _object { PyObject_HEAD } PyObject; typedef struct { PyObject_VAR_HEAD } PyVarObject; 同一个文件下也定义了相应的两个宏. 可以看出Python中对象的核心在于引用计数ob_refcnt和类型对象ob

shelve 用来持久化任意的Python对象实例代码_python

shelve -- 用来持久化任意的Python对象 这几天接触了Python中的shelve这个module,感觉比pickle用起来更简单一些,它也是一个用来持久化Python对象的简单工具.当我们写程序的时候如果不想用关系数据库那么重量级的东东去存储数据,不妨可以试试用shelve.shelf也是用key来访问的,使用起来和字典类似.shelve其实用anydbm去创建DB并且管理持久化对象的.  创建一个新的shelf 直接使用shelve.open()就可以创建了 import she

【Python】python对象与json相互转换

在网络通信中,json是一种常用的数据格式,对于python来讲,将类转化为json数据以及将json数据转化为对象是一件非常容易的事情. 下面给出两者转化的方法 # -*- coding: UTF-8 -*- import json #自定义类 class MyClass: #初始化 def __init__(self): self.a=2 self.b='bb' ########################## #创建MyClass对象 myClass=MyClass() #添加数据c