最近对Python 的对象引用机制稍微研究了一下,留下笔记,以供查阅。

首先有一点是明确的:「Python 中一切皆对象」。

那么,这到底意味着什么呢?

如下代码:

#!/usr/bin/env python

a= [0, 1, 2] #来个简单的list

#最初,list 和其中各个元素的id 是这样的。

print 'origin'

printid(a),afor x ina:printid(x), xprint '----------------------'

#我们把第一个元素改改

print 'after change a[0]'a[0]= 4

printid(a),afor x ina:printid(x), xprint '----------------------'

#我们再把第二个元素改改

print 'after change a[1]'a[1] = 5

printid(a),afor x ina:printid(x), xprint '----------------------'

#回头看看直接写个0 ,id是多少

print 'how about const 0?'

print id(0), 0

运行结果如下:

PastgiftMacbookPro:python pastgift$ ./refTest.py

Origin4299760200 [0, 1, 2]429818132804298181304 1

4298181280 2

----------------------after change a[0]4299760200 [4, 1, 2]4298181232 4

4298181304 1

4298181280 2

----------------------after change a[1]4299760200 [4, 5, 2]4298181232 4

4298181208 5

4298181280 2

----------------------how about const 0?4298181328 0

从「Origin」部分来看,list 中各个元素的地址之间都正好相差24,依次指向各自的数据——这让我想到了数组。

当修改a[0] 的值之后,发现,a[0] 的地址发生了变化。也就是说,赋值语句实际上只是让a[0] 重新指向另一个对象而已。此外,还注意到,a[0] 的地址和a[2]的地址相差48(2个24)。

当再次修改a[1] 之后,同样地,a[1] 的地址也发生变化,有趣的是,这次a[1] 的地址和a[0] 的地址又相差24,和原先的a[2] 相差72(3个24)。

最后,当直接把数字0的地址打印出来后,发现它的地址和最开始的a[0] 的地址完全一样。

至此,基本可以说明,就算是list 中的元素,其实也是引用。修改list 中的元素,实际上还是在修改引用而已。

对于Python 中类属性,有人提到过「类属性在同一类及其子类之间共享,修改类属性会影响到同一类及其子类的所有对象」。

这里提到的:http://www.cnblogs.com/vamei/archive/2012/06/02/2532018.html

听着挺吓人,但仔细研究之后,其实倒也不是什么大不了的事情。

如下代码:

#!/usr/bin/env python

classBird(object):

name= 'bird'talent= ['fly']classChicken(Bird):passbird=Bird();

bird2= Bird(); #同类实例

chicken = Chicken(); #子类实例

#最开始是这样的

print 'Original attr'

printid(bird.name), bird.nameprintid(bird.talent), bird.talentprintid(bird2.name), bird2.nameprintid(bird2.talent), bird2.talentprintid(chicken.name), chicken.nameprintid(chicken.talent), chicken.talentprint '----------------------------'

#换个名字看看

bird.name = 'bird name changed!'

print 'after changing name'

printid(bird.name), bird.nameprintid(bird.talent), bird.talentprintid(bird2.name), bird2.nameprintid(bird2.talent), bird2.talentprintid(chicken.name), chicken.nameprintid(chicken.talent), chicken.talentprint '----------------------------'

#洗个天赋试试(修改类属性中的元素)

bird.talent[0] = 'walk'

print 'after changing talent(a list)'

printid(bird.name), bird.nameprintid(bird.talent), bird.talentprintid(bird2.name), bird2.nameprintid(bird2.talent), bird2.talentprintid(chicken.name), chicken.nameprintid(chicken.talent), chicken.talentprint '----------------------------'

#换个新天赋树(整个类属性全换掉)

bird.talent = ['swim']print 'after reassign talent'

printid(bird.name), bird.nameprintid(bird.talent), bird.talentprintid(bird2.name), bird2.nameprintid(bird2.talent), bird2.talentprintid(chicken.name), chicken.nameprintid(chicken.talent), chicken.talentprint '----------------------------'

#洗掉新天赋树(对新来的类属性中的元素进行修改)

bird.talent[0] = 'dance'

print 'changing element after reassigning talent'

printid(bird.name), bird.nameprintid(bird.talent), bird.talentprintid(bird2.name), bird2.nameprintid(bird2.talent), bird2.talentprintid(chicken.name), chicken.nameprintid(chicken.talent), chicken.talentprint '----------------------------'

运行结果:

PastgiftMacbookPro:python pastgift$ ./changeAttributeTest.py

Original attr4301998000bird4301857352 ['fly']4301998000bird4301857352 ['fly']4301998000bird4301857352 ['fly']----------------------------after changing name4301986984bird name changed!4301857352 ['fly']4301998000bird4301857352 ['fly']4301998000bird4301857352 ['fly']----------------------------after changing talent(a list)4301986984bird name changed!4301857352 ['walk']4301998000bird4301857352 ['walk']4301998000bird4301857352 ['walk']----------------------------after reassign talent4301986984bird name changed!4301859512 ['swim']4301998000bird4301857352 ['walk']4301998000bird4301857352 ['walk']----------------------------changing element after reassigning talent4301986984bird name changed!4301859512 ['dance']4301998000bird4301857352 ['walk']4301998000bird4301857352 ['walk']----------------------------

在「Origin」的时候,同类对象,子类对象的相同类属性的地址都是相同的——这就是所谓的「共享」。

修改name 之后,只有被修改的对象name 属性发生变化。这是因为对name的赋值操作实际上就是换了一个字符串,重新引用。字符串本身并没有发生变化。所以并没有在同类和子类之间产生互相影响。

接下来,修改talent 中的元素。这时,情况有所改变:同类及其子类的talent 属性都一起跟着变了——这很好理解,因为它们都引用的内存地址都一样,引用的是同一个对象。

再接下来,给talent 重新赋值,也就是改成引用另外一个对象。结果是只有本实例的talent 属性变化了。从内存地址可以看出,本实例和其他实例的talent 属性已经不再指向相同的对象了。就是说「至此,本实例已经是圈外人士了」。

那么,最后再次修改talent 中元素后,对其他实例无影响的结果也是很好理解了。因为已经是「圈外人士」了嘛,我再怎么折腾也都是自己的事情了。

所以,「类属性在同类及其子类之间互相影响」必须有一个前提条件:实例建立后,其类属性从来没有被重新赋值过,即类属性依然指向最初所指向的内存地址。

最后提一下对象属性

如下代码:

#!/usr/bin/env python

classBird(object):def __init__(self):

self.talent= ['fly']

bird=Bird()

bird2=Bird()#刚开始的情形

print 'Origin'

printid(bird.talent), bird.talentprintid(bird2.talent), bird2.talentprint '--------------------'

#修改其中一个对象的属性

bird.talent[0] = 'walk'

print 'after changing attribute'

printid(bird.talent), bird.talentprintid(bird2.talent), bird2.talentprint '--------------------'

#作死:两个对象的属性指向同一个内存地址,再修改

bird.talent =bird2.talent

bird.talent[0]= 'swim'

print 'assign to another attribute and change it'

printid(bird.talent), bird.talentprintid(bird2.talent), bird2.talentprint '--------------------'

运行结果:

PastgiftMacbookPro:python pastgift$ ./changeAttributeTest2.py

Origin4299867632 ['fly']4299760200 ['fly']--------------------after changing attribute4299867632 ['walk']4299760200 ['fly']--------------------assign to another attributeandchange it4299760200 ['swim']4299760200 ['swim']--------------------

由于对象属性就算内容完全一样(刚初始化后的属性内容一般都是一样的),也会分配到完全不同的内存地址上去。所以不存在「同类对象之间影响」的情况。

但如果让一个对象的属性和另一个对象的属性指向同一个地址,两者之间(但也仅限两者之间)便又互相牵连起来。

python中的引用类型_Python 中的引用和类属性的初步理解相关推荐

  1. 非常易于理解‘类'与'对象’ 间 属性 引用关系,暨《Python 中的引用和类属性的初步理解》读后感...

    关键字:名称,名称空间,引用,指针,指针类型的指针(即指向指针的指针) 我读完后的理解总结: 1. 我们知道,python中的变量的赋值操作,变量其实就是一个名称name,赋值就是将name引用到一个 ...

  2. python中的引用类型_Python中的值类型与引用类型

    其实各个标准资料中没有说明Python有值类型和引用类型的分类,这个分类一般是C++和Java中的.但是语言是相通的,所以Python肯定也有类似的.实际上Python 的变量是没有类型的,这与以往看 ...

  3. python算法和数据结构_Python中的数据结构和算法

    python算法和数据结构 To 至 Leonardo da Vinci 达芬奇(Leonardo da Vinci) 介绍 (Introduction) The purpose of this ar ...

  4. python中定义数据结构_Python中的数据结构—简介

    python中定义数据结构 You have multiples algorithms, the steps of which require fetching the smallest value ...

  5. python怎么调用文件_python 中如何引用头文件

    python 引入 导入 自定义模块, python 引入 导入 外部文件 python 引入 导入 自定义模块, python 引入  导入 外部文件 项目中想使用以前的代码,或者什么样的需求致使你 ...

  6. python 下标 遍历列表_python中的数据结构与算法(1):列表、元组与字符串

    列表是 python 中最常用.最重要的数据结构之一. 一般来说,我们用列表来管理一组数据对象,这些对象可能是同一类型,也可能是不同类型.列表不仅记录了这些数据对象,而且也记录了它们之间的一种顺序关系 ...

  7. python列表对象相同_Python中的学习列表对象,List

    List(列表) 是 Python 中使用最频繁的数据类型. 列表可以完成大多数集合类的数据结构实现.列表中元素的类型可以不相同,它支持数字,字符串甚至可以包含列表(所谓嵌套). 列表是写在方括号 [ ...

  8. python怎么清理垃圾_Python 中的“垃圾”是怎么回收的?

    前言 对于python来说,一切皆为对象,所有的变量赋值都遵循着对象引用机制.程序在运行的时候,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量:计算完成后,再将结果输出到永久性存储器中.如果 ...

  9. python关键字详解_Python 中的关键字with详解

    在 Python 2.5 中,with关键字被加入.它将常用的 try ... except ... finally ...模式很方便的被复用.看一个最经典的例子: with open('file.t ...

最新文章

  1. 啊D扫肉鸡+无远控双开XP3389 termsrvhack.dll_本地测试
  2. LeetCode Max Points on a Line
  3. create 执行存储过程报错出现符号_年薪百万之路--第四十天 存储引擎
  4. linux oracle目录权限不够,Linux 目录权限不足导致ORA-39070错误 | 信春哥,系统稳,闭眼上线不回滚!...
  5. 控制台双缓冲防闪烁--功能封装
  6. double+float
  7. java最常见的runtime_Java常见runtime exception
  8. EasyUI中Datagrid列定位方法
  9. Docker 方式搭建 Prometheus + grafana
  10. 只要学会它,再多 Bug 也不怕
  11. 人脸表情识别从0到部署,猜猜『轮到你了』的微笑狼人到底是谁!
  12. 笔试题:简述以下两个for循环的优缺点
  13. NTKO Office乱码问题
  14. 计算机里电子 邮件格式,邮箱格式怎么写?
  15. DotNet 资源大全(转)
  16. Why the MonthCalendar.MinDate is 01/01/1753?
  17. Dlink DIR-615L 和水星(mercury) MW300R桥接方法!
  18. 在Win10系统下使用与安装metis
  19. JT/T808模拟器、企业压测工具使用
  20. Java实现微信小程序文本内容敏感词检查

热门文章

  1. c++编程例子_如何开始厉害的C语言编程?大神都是这样开始的!
  2. 合工大五套卷_2021森哥五套卷(五)
  3. 职称计算机考试选择题,职称计算机考试综合选择题「附答案」.docx
  4. 2016计算机有哪些专业知识点,2016计算机专业知识:精选知识点练习(99)
  5. 图数据库应用系列(一):金融智能风控
  6. setuptools与distutils的区别
  7. 麒麟操作系统配置网络_讲解银河麒麟桌面操作系统
  8. 【项目管理】ITTO-相关方管理
  9. 【中间件】消息队列-RabbitMQ
  10. 信息系统项目管理师:第9章:项目人力资源管理(2)-章节重点