Python 中的引用和类属性的初步理解
最近对Python 的对象引用机制稍微研究了一下,留下笔记,以供查阅。
首先有一点是明确的:「Python 中一切皆对象」。
那么,这到底意味着什么呢?
如下代码:
#!/usr/bin/env python a = [0, 1, 2] # 来个简单的list # 最初,list 和其中各个元素的id 是这样的。
print 'origin'
print id(a),a
for x in a:
print id(x), x
print '----------------------' # 我们把第一个元素改改
print 'after change a[0]'
a[0] = 4
print id(a),a
for x in a:
print id(x), x
print '----------------------' # 我们再把第二个元素改改
print 'after change a[1]'
a[1] = 5
print id(a),a
for x in a:
print id(x), x
print '----------------------' # 回头看看直接写个0 ,id是多少
print 'how about const 0?'
print id(0), 0
运行结果如下:
PastgiftMacbookPro:python pastgift$ ./refTest.py
Origin
4299760200 [0, 1, 2]
4298181328 0
4298181304 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 class Bird(object):
name = 'bird'
talent = ['fly'] class Chicken(Bird):
pass bird = Bird();
bird2 = Bird(); # 同类实例
chicken = Chicken(); # 子类实例 # 最开始是这样的
print 'Original attr'
print id(bird.name), bird.name
print id(bird.talent), bird.talent
print id(bird2.name), bird2.name
print id(bird2.talent), bird2.talent
print id(chicken.name), chicken.name
print id(chicken.talent), chicken.talent
print '----------------------------' # 换个名字看看
bird.name = 'bird name changed!' print 'after changing name'
print id(bird.name), bird.name
print id(bird.talent), bird.talent
print id(bird2.name), bird2.name
print id(bird2.talent), bird2.talent
print id(chicken.name), chicken.name
print id(chicken.talent), chicken.talent
print '----------------------------' # 洗个天赋试试(修改类属性中的元素)
bird.talent[0] = 'walk' print 'after changing talent(a list)'
print id(bird.name), bird.name
print id(bird.talent), bird.talent
print id(bird2.name), bird2.name
print id(bird2.talent), bird2.talent
print id(chicken.name), chicken.name
print id(chicken.talent), chicken.talent
print '----------------------------' # 换个新天赋树(整个类属性全换掉)
bird.talent = ['swim'] print 'after reassign talent'
print id(bird.name), bird.name
print id(bird.talent), bird.talent
print id(bird2.name), bird2.name
print id(bird2.talent), bird2.talent
print id(chicken.name), chicken.name
print id(chicken.talent), chicken.talent
print '----------------------------' # 洗掉新天赋树(对新来的类属性中的元素进行修改)
bird.talent[0] = 'dance' print 'changing element after reassigning talent'
print id(bird.name), bird.name
print id(bird.talent), bird.talent
print id(bird2.name), bird2.name
print id(bird2.talent), bird2.talent
print id(chicken.name), chicken.name
print id(chicken.talent), chicken.talent
print '----------------------------'
运行结果:
PastgiftMacbookPro:python pastgift$ ./changeAttributeTest.py
Original attr
4301998000 bird
4301857352 ['fly']
4301998000 bird
4301857352 ['fly']
4301998000 bird
4301857352 ['fly']
----------------------------
after changing name
4301986984 bird name changed!
4301857352 ['fly']
4301998000 bird
4301857352 ['fly']
4301998000 bird
4301857352 ['fly']
----------------------------
after changing talent(a list)
4301986984 bird name changed!
4301857352 ['walk']
4301998000 bird
4301857352 ['walk']
4301998000 bird
4301857352 ['walk']
----------------------------
after reassign talent
4301986984 bird name changed!
4301859512 ['swim']
4301998000 bird
4301857352 ['walk']
4301998000 bird
4301857352 ['walk']
----------------------------
changing element after reassigning talent
4301986984 bird name changed!
4301859512 ['dance']
4301998000 bird
4301857352 ['walk']
4301998000 bird
4301857352 ['walk']
----------------------------
在「Origin」的时候,同类对象,子类对象的相同类属性的地址都是相同的——这就是所谓的「共享」。
修改name 之后,只有被修改的对象name 属性发生变化。这是因为对name的赋值操作实际上就是换了一个字符串,重新引用。字符串本身并没有发生变化。所以并没有在同类和子类之间产生互相影响。
接下来,修改talent 中的元素。这时,情况有所改变:同类及其子类的talent 属性都一起跟着变了——这很好理解,因为它们都引用的内存地址都一样,引用的是同一个对象。
再接下来,给talent 重新赋值,也就是改成引用另外一个对象。结果是只有本实例的talent 属性变化了。从内存地址可以看出,本实例和其他实例的talent 属性已经不再指向相同的对象了。就是说「至此,本实例已经是圈外人士了」。
那么,最后再次修改talent 中元素后,对其他实例无影响的结果也是很好理解了。因为已经是「圈外人士」了嘛,我再怎么折腾也都是自己的事情了。
所以,「类属性在同类及其子类之间互相影响」必须有一个前提条件:实例建立后,其类属性从来没有被重新赋值过,即类属性依然指向最初所指向的内存地址。
最后提一下对象属性
如下代码:
#!/usr/bin/env python class Bird(object):
def __init__(self):
self.talent = ['fly'] bird = Bird()
bird2 = Bird() # 刚开始的情形
print 'Origin'
print id(bird.talent), bird.talent
print id(bird2.talent), bird2.talent
print '--------------------' # 修改其中一个对象的属性
bird.talent[0] = 'walk' print 'after changing attribute'
print id(bird.talent), bird.talent
print id(bird2.talent), bird2.talent
print '--------------------' # 作死:两个对象的属性指向同一个内存地址,再修改
bird.talent = bird2.talent
bird.talent[0] = 'swim' print 'assign to another attribute and change it'
print id(bird.talent), bird.talent
print id(bird2.talent), bird2.talent
print '--------------------'
运行结果:
PastgiftMacbookPro:python pastgift$ ./changeAttributeTest2.py
Origin
4299867632 ['fly']
4299760200 ['fly']
--------------------
after changing attribute
4299867632 ['walk']
4299760200 ['fly']
--------------------
assign to another attribute and change it
4299760200 ['swim']
4299760200 ['swim']
--------------------
由于对象属性就算内容完全一样(刚初始化后的属性内容一般都是一样的),也会分配到完全不同的内存地址上去。所以不存在「同类对象之间影响」的情况。
但如果让一个对象的属性和另一个对象的属性指向同一个地址,两者之间(但也仅限两者之间)便又互相牵连起来。
Python 中的引用和类属性的初步理解的更多相关文章
- 非常易于理解‘类'与'对象’ 间 属性 引用关系,暨《Python 中的引用和类属性的初步理解》读后感
关键字:名称,名称空间,引用,指针,指针类型的指针(即指向指针的指针) 我读完后的理解总结: 1. 我们知道,python中的变量的赋值操作,变量其实就是一个名称name,赋值就是将name引用到一个 ...
- Python 中使用动态创建类属性的机制实现接口之后的依赖
我们在自动化测试中经常会需要关联用例处理,需要动态类属性: 推荐使用第二种方法: 创建:setattr() 获取:getattr() 两种,如何创建 类属性 loan_id # 第一种,创建 # 类名 ...
- python中的引用传递,可变对象,不可变对象,list注意点
python中的引用传递 首先必须理解的是,python中一切的传递都是引用(地址),无论是赋值还是函数调用,不存在值传递. 可变对象和不可变对象 python变量保存的是对象的引用,这个引用指向堆内 ...
- python学习之【第十七篇】:Python中的面向对象(类和对象)
1.什么是类和类的对象? 类是一种数据结构,我们可以用它来定义对象,后者把数据值和行为特性融合在一起,类是现实世界的抽象的实体以编程形式出现.实例是这些对象的具体化.类是用来描述一类事物,类的对象指的 ...
- python中的引用
作为一个python初学者,今天被一个python列表和词典引用的问题折磨了很久,但其实了解了缘由也很简单,记录在此备忘. 首先背书python中的引用对象问题: 1. python不允许程序员选择采 ...
- Python中的引用的使用注意
关于Python中的引用的一些使用注意 在python中,在创建一个对象并给它赋予一个变量时,这个赋予的变量仅仅是一个引用它所代表的对象.也就是说新创建的对象只是指向计算机中储存那个对象的内存. 比如 ...
- python中如何统计一个类的实例化对象
类中的静态变量 需要通过类名.静态变量名 来修改 :通过对象不能修改 python中如何统计一个类的实例化对象?? class Person: #静态变量count,用于记录类被实例化的次数 coun ...
- 关于如何在Python中使用静态、类或抽象方法的权威指南
Python中方法的工作方式 方法是存储在类属性中的函数,你可以用下面这种方式声明和访问一个函数 >>> class Pizza(object): ... def __init__( ...
- 22.python中的面向对象和类的基本语法
当我发现要写python的面向对象的时候,我是踌躇满面,坐立不安呀.我一直在想:这个坑应该怎么爬?因为python中关于面向对象的内容很多,如果要讲透,最好是用面向对象的思想重新学一遍前面的内容.这个 ...
随机推荐
- Linux 下安装配置nginx及常见问题解答
其实也不能完全算是原创吧!都是我配置nginx时所遇到的问题,查阅资料后总结起来.即是巩固一下nginx的配置,也是分享给新入Linux的童鞋们一些知识 好了,不多废话,进入主题吧! 为nginx添加 ...
- CF Amr and Pins (数学)
Amr and Pins time limit per test 1 second memory limit per test 256 megabytes input standard input o ...
- insert 另外一种用法
then into dept01(id) values(deptno) then into dept02(id) values(deptno) else into dept03(id) values( ...
- 使用C#动态生成Word文档/Excel文档的程序测试通过后,部署到IIS服务器上,不能正常使用的问题解决方案
使用C#动态生成Word文档/Excel文档的程序功能调试.测试通过后,部署到服务器上,不能正常使用的问题解决方案: 原因: 可能asp.net程序或iis访问excel组件时权限不够(Ps:Syst ...
- Tomcat - 设置 HTTP 基本认证
在 Tomcat 中设置 HTTP 基本认证的示例 在 $TOMCAT_HOME\conf\tomcat-users.xml 文件中配置角色和用户: <tomcat-users> < ...
- Service通信详解
1.使用Intent进行异步通讯 在Service任务一旦完成后,就发送广播.开发者只需要实现一个BroadcastReceiver来监听响应既可. Activity.startService启动in ...
- response小结(四)
1.发送http头,控制浏览器定时刷新网页(REFRESH). package com.yyz.response; import java.io.IOException; import javax.s ...
- 微软的技术态度 -- 从其对于CRT的设计考虑说起
很多人从C语言学习过来的人都知道,在编写程序时用到的像printf这样的函数,是作为该语言标准库函数提供的,这也是C语言标准中规定的内容.因此,操作系统必须对其保持一定程度上的透明,也就是说,作为一个 ...
- 第五十六篇、OC打开本地和网络上的word、ppt、excel、text等文件
iOS打开本地和网络上的word.ppt.excel.text等文件 iOS开发过程中可能需要预览一些文件,这些文件的格式可能有word.ppt.excel等文件格式.那么系统提供两个类去预览这些文件 ...
- 第三十九篇、NavBar动态隐藏、设置透明、毛玻璃效果
1.动态隐藏 - (void)viewDidLoad { [super viewDidLoad]; if ([self respondsToSelector:@selector(automatical ...