在python中,万物皆对象,常见的整数、浮点数、字符串、元祖、列表等类型,以及各种class、class instance等等都是对象。这些对象在python解释器内部的地址是怎样的呢?这里我们只简单看下python对象内存地址的相关基础知识,以及编码过程中一些注意事项,关于python解释器的内存管理机制,涉及到解释器内核的内存池原理,这里不做深入探讨,有兴趣的朋友可以去阅读解释器源代码。

0x01 不可变对象

    不可变对象是指对象的内存值不能被改变。Python中变量以引用的方式指向对象,如果变量引用了不可变对象,当改变该变量时,由于其所指的对象的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址,即变量引用了新的对象。

    数值类型(整数和浮点)、字符串str、元组tuple都是不可变类型。比如a=1,b=[1],c={'a':1},id(a)、id(b[0])、id(1)、id(c['a'])将输出一样的值,因为1是不可变对象,其在内存中是不可改变的。

0x02 可变对象

可变对象是指对象的内存值可以被改变,变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的内存地址,通俗点说就是原地改变。列表list、字典dict、集合set是可变类型。

0x03 对象的内存地址

可以使用内置函数id()查看python对象的内存地址。下面是一些注意事项:

(1) python中所有数字、字符串、list等值,创建时会分配内存空间,变量通过引用的方式使用它们。比如a=1和b=1,id(a)和id(b)的输出一样,表示a和b都指向相同的内存地址,即引用了同一个不可变对象;但是a=[1]和b=[1],id(a)和id(b)将输出不一样的值,a和b指向的是不同的内存地址,即引用了不同的可变对象,说明各可变对象是相互独立的,在内存中有独立的内存地址

(2) 可用 is 判断两个对象的id(即内存地址)是否一样,用 == 判断两个对象的值是否一样。None值也有内存地址

(3) list、set对象有各自的独立内存空间,他们的各元素以引用的方式指向可变、不可变对象;

(4) 函数形参的默认值,在内存中会开辟独立的内存空间。比如测试代码中test函数的param参数,其默认值是空list,如果调用时未传参,则param指向内存中预先分配好的地址,该地址存储的是list类型的值;当调用时传参为a,则param引用了a指向的内存空间;

(5) python使用引用计数和垃圾回收来释放内存对象,每个内存对象都维护了一个引用计数,包括各种数字、字符串、list、set等类型值,以及类实例对象等等,当这些对象的引用计数为 0 时,会被解释器回收内存。每次对对象进行引用操作,都会导致其引用计数加1, 如下面测试代码中的整数1,列表a、b、c、d、n都引用了整数1,以及test函数中的append操作,都会导致数字1的引用计数加1

(6) copy和deepcopy方法都创建了新的内存对象,如测试代码中的b和c都是新的变量,其各个元素可能是指向同一个内存空间。赋值操作是指向同一个内存块,同时增加引用计数。copy是浅拷贝,deepcopy是深拷贝,特别对于可变对象,copy是以引用的方式指向同一个可变对象,而deepcopy会开辟新的内存地址,也就是创建了新的可变对象。

0x04 测试代码

# -*- coding: utf8 -*-
import copy
import sysa = [1, 2, [3, 4]]
b = copy.copy(a)
c = copy.deepcopy(a)
d = aprint 'address of a:', id(a)
print 'address of b:', id(b)
print 'address of c:', id(c)
print 'address of d:', id(d)
print 'address of 1:', id(1)
print 'address of element 0 in a:', id(a[0])
print 'address of element 0 in b:', id(b[0])
print 'address of element 0 in c:', id(c[0])
print 'a=', a
print 'b=', b
print 'c=', c
print 'd=', da[0] = 99
print 'a=', a
print 'b=', b
print 'c=', c
print 'd=', dprint 'address of element 0 in a:', id(a[0])
print 'address of element 0 in b:', id(b[0])
print 'address of element 0 in c:', id(c[0])print 'address of element 2 in a:', id(a[2])
print 'address of element 2 in b:', id(b[2])
print 'address of element 2 in c:', id(c[2])a[2].append(5)
print 'a=', a
print 'b=', b
print 'c=', c
print 'd=', ddef test(param=[]):print 'address of param:', id(param)param.append(1)print 'reference count of 1:', sys.getrefcount(1)return paramprint test(a)
print test()
print test()
print 'a=', a
print 'b=', b
print 'c=', c
print 'd=', dprint 'reference count of 1:', sys.getrefcount(1)
n = 1
print 'reference count of 1:', sys.getrefcount(1)
del n
print 'reference count of 1:', sys.getrefcount(1)

0x06 运行结果

address of a: 54681224
address of b: 54716296
address of c: 54692104
address of d: 54681224
address of 1: 48258856
address of element 0 in a: 48258856
address of element 0 in b: 48258856
address of element 0 in c: 48258856
a= [1, 2, [3, 4]]
b= [1, 2, [3, 4]]
c= [1, 2, [3, 4]]
d= [1, 2, [3, 4]]
a= [99, 2, [3, 4]]
b= [1, 2, [3, 4]]
c= [1, 2, [3, 4]]
d= [99, 2, [3, 4]]
address of element 0 in a: 48260488
address of element 0 in b: 48258856
address of element 0 in c: 48258856
address of element 2 in a: 54692232
address of element 2 in b: 54692232
address of element 2 in c: 54716360
a= [99, 2, [3, 4, 5]]
b= [1, 2, [3, 4, 5]]
c= [1, 2, [3, 4]]
d= [99, 2, [3, 4, 5]]
address of param: 54681224
reference count of 1: 161
[99, 2, [3, 4, 5], 1]
address of param: 54716424
reference count of 1: 162
[1]
address of param: 54716424
reference count of 1: 163
[1, 1]
a= [99, 2, [3, 4, 5], 1]
b= [1, 2, [3, 4, 5]]
c= [1, 2, [3, 4]]
d= [99, 2, [3, 4, 5], 1]
reference count of 1: 163
reference count of 1: 164
reference count of 1: 163

Python对象内存地址相关推荐

  1. flask-admin初次使用遇到的几个小问题(显示对象内存地址,编辑无法正确跳转)

    1.flask-admin显示列时如果为列为relationship ,就会显示对象内存地址 我的orm类的 ​​​​​​ 当我想显示Item的place.plaec_name 时我一开始是这样写的 ...

  2. python参数内存地址

    python参数内存地址 1.参数内存地址 查看某个值在内存中的地址 v1=123 id(v1) 函数值执行参数时,传递的是内存地址 #函数执行传参,传递的是内存地址 def func(data):p ...

  3. python对象内存模型

    原文:Python的垃圾回收机制(二)之内存模型 1. Python对象内存模型 首先介绍一下Python对象的内存模型,如下图1所示: 图1. PyObject对象内存模型 上图可以看到,一个PyO ...

  4. Java获取对象内存地址

    haseCode()方法获取并非对象内存地址 hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,获取对象散列的地址,并非实际内存地址. java直接打印对象,结果是十六进制的散列地址 ...

  5. 深入分析Java中打印对象内存地址 System.identityHashCode()方法

    文章目录 地址是什么样子的 toString()方法 重写hashCode identityHashCode与真正的内存地址 参考 地址是什么样子的 我们知道system.out.println(ne ...

  6. python查看内存地址的内容_python中如何查看指定内存地址的内容

    python中一般并不需要查看内存内容,但作为从C/C++过来的人,有的时候还是想看看内存,有时是为了验证内容是否与预期一致,有时是为了探究下内存布局. from sys import getsize ...

  7. python获取内存地址上存储的值

    在python中,可以通过id()这个方法来获取对象的内存地址. 但是反过来,怎么获取内存地址上存储的值? 先看一段代码: from ctypes import string_at from sys ...

  8. python查看内存地址

    1.查看python内存地址 python 通过id查看内存地址 eg: a=1 print(id(a))#输出94486697843200 2.不可变量 不可变对象是指对象的内存值不能被改变.Pyt ...

  9. Java中打印对象内存地址

    Object的hashCode()默认是返回内存地址的,但是hashCode()可以重写,所以hashCode()不能代表内存地址的不同 System.identityHashCode(Object) ...

  10. 列表中的字符串成员 转化为 整型成员 。如:将[‘2‘, ‘1‘] 转化为:[2, 1]、map()返回的是一个可迭代对象内存地址、join(可迭代对象),要注意:可迭代对象中的成员必须是字符串类型

    注意: 1.map()返回的是一个可迭代对象的内存地址,如果要看它具体的值,有两种方式: 法1:在map()前面,加list( ).tuple( ).set( ),将它强制转化为列表.元组.集合类型. ...

最新文章

  1. 连接控制台_智能消防水炮视频系统连接方法
  2. 在linux c 以结构体形式写文件 结构体参数如何在函数中传递,Linux安全审计机制模块实现分析(16)-核心文件之三auditsc.c文件描述及具体变量、函数定义...
  3. Volatile可见性、缓存一致性协议、指令重排、内存屏障 - 手写笔记
  4. 内核kernel以及根文件系统rootfs是如何映射到对应的nand flash的
  5. python映射实体类_【HIBERNATE框架开发之二】第一个HIBERNATE-ANNONATION项目(采用@ENTITY、@ID直接映射实体类)...
  6. Linux批量复制文件夹里的文件到另一个文件夹(问题:linux sh: /bin/cp: Argument list too long )
  7. telegram定时消息_ActiveMQ(18):Message之延迟和定时消息投递
  8. 项目常用工具类整理(一)--时间工具类DateUtil.java
  9. http://book.ifeng.com/lianzai/detail_2011_05/08/6243572_37.shtml
  10. torch tensor去掉1维_代数拓扑笔记(1) —— 胞腔复形
  11. Git merge合并冲突 error: ‘merge‘ is not possible because you have unmerged files的解决方法
  12. 全网稀缺,完整链家地图找房的实现(一)
  13. Richer Convolutional Features for Edge Detection(RCF论文学习笔记)
  14. CSS3 盒子设置border和padding不撑开盒子
  15. Numpy IO:npy、npz
  16. 基于矢量的水下路由协议
  17. linux cadaver 命令,备份Linux操作系统的数据到坚果云的方法
  18. NumPy库回顾与分享(一)
  19. CCF认证练习题-西西艾弗岛的购物中心
  20. Packet Tracer6.0静态路由,RIP,OSPF路由方案配置(1)

热门文章

  1. 一个90后草根站长的内心独白
  2. c语言修改注册表函数,用C语言实现修改注册表
  3. JanusGraph详解
  4. 【discuzx2】如何通过工具修改ucenter创始人的管理员密码以保证通信成功?
  5. JavaScript---BOM和DOM
  6. RTI_DDS自定义插件开发 10 官方案例
  7. canopen和1939区别_现场总线SAE J1939 与CANopen 通讯
  8. apkg格式怎么打开_天正软件如何导成CAD识别格式
  9. rk3568 android11 的 hardware架构学习纪要
  10. python爬公众号文章_python爬取指定微信公众号文章