python中的引用类型_Python 中的引用和类属性的初步理解
最近对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 中的引用和类属性的初步理解相关推荐
- 非常易于理解‘类'与'对象’ 间 属性 引用关系,暨《Python 中的引用和类属性的初步理解》读后感...
关键字:名称,名称空间,引用,指针,指针类型的指针(即指向指针的指针) 我读完后的理解总结: 1. 我们知道,python中的变量的赋值操作,变量其实就是一个名称name,赋值就是将name引用到一个 ...
- python中的引用类型_Python中的值类型与引用类型
其实各个标准资料中没有说明Python有值类型和引用类型的分类,这个分类一般是C++和Java中的.但是语言是相通的,所以Python肯定也有类似的.实际上Python 的变量是没有类型的,这与以往看 ...
- python算法和数据结构_Python中的数据结构和算法
python算法和数据结构 To 至 Leonardo da Vinci 达芬奇(Leonardo da Vinci) 介绍 (Introduction) The purpose of this ar ...
- python中定义数据结构_Python中的数据结构—简介
python中定义数据结构 You have multiples algorithms, the steps of which require fetching the smallest value ...
- python怎么调用文件_python 中如何引用头文件
python 引入 导入 自定义模块, python 引入 导入 外部文件 python 引入 导入 自定义模块, python 引入 导入 外部文件 项目中想使用以前的代码,或者什么样的需求致使你 ...
- python 下标 遍历列表_python中的数据结构与算法(1):列表、元组与字符串
列表是 python 中最常用.最重要的数据结构之一. 一般来说,我们用列表来管理一组数据对象,这些对象可能是同一类型,也可能是不同类型.列表不仅记录了这些数据对象,而且也记录了它们之间的一种顺序关系 ...
- python列表对象相同_Python中的学习列表对象,List
List(列表) 是 Python 中使用最频繁的数据类型. 列表可以完成大多数集合类的数据结构实现.列表中元素的类型可以不相同,它支持数字,字符串甚至可以包含列表(所谓嵌套). 列表是写在方括号 [ ...
- python怎么清理垃圾_Python 中的“垃圾”是怎么回收的?
前言 对于python来说,一切皆为对象,所有的变量赋值都遵循着对象引用机制.程序在运行的时候,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量:计算完成后,再将结果输出到永久性存储器中.如果 ...
- python关键字详解_Python 中的关键字with详解
在 Python 2.5 中,with关键字被加入.它将常用的 try ... except ... finally ...模式很方便的被复用.看一个最经典的例子: with open('file.t ...
最新文章
- 啊D扫肉鸡+无远控双开XP3389 termsrvhack.dll_本地测试
- LeetCode Max Points on a Line
- create 执行存储过程报错出现符号_年薪百万之路--第四十天 存储引擎
- linux oracle目录权限不够,Linux 目录权限不足导致ORA-39070错误 | 信春哥,系统稳,闭眼上线不回滚!...
- 控制台双缓冲防闪烁--功能封装
- double+float
- java最常见的runtime_Java常见runtime exception
- EasyUI中Datagrid列定位方法
- Docker 方式搭建 Prometheus + grafana
- 只要学会它,再多 Bug 也不怕
- 人脸表情识别从0到部署,猜猜『轮到你了』的微笑狼人到底是谁!
- 笔试题:简述以下两个for循环的优缺点
- NTKO Office乱码问题
- 计算机里电子 邮件格式,邮箱格式怎么写?
- DotNet 资源大全(转)
- Why the MonthCalendar.MinDate is 01/01/1753?
- Dlink DIR-615L 和水星(mercury) MW300R桥接方法!
- 在Win10系统下使用与安装metis
- JT/T808模拟器、企业压测工具使用
- Java实现微信小程序文本内容敏感词检查
热门文章
- c++编程例子_如何开始厉害的C语言编程?大神都是这样开始的!
- 合工大五套卷_2021森哥五套卷(五)
- 职称计算机考试选择题,职称计算机考试综合选择题「附答案」.docx
- 2016计算机有哪些专业知识点,2016计算机专业知识:精选知识点练习(99)
- 图数据库应用系列(一):金融智能风控
- setuptools与distutils的区别
- 麒麟操作系统配置网络_讲解银河麒麟桌面操作系统
- 【项目管理】ITTO-相关方管理
- 【中间件】消息队列-RabbitMQ
- 信息系统项目管理师:第9章:项目人力资源管理(2)-章节重点