最近对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 中类属性,有人提到过「类属性在同一类及其子类之间共享,修改类属性会影响到同一类及其子类的所有工具」。
听着挺吓人,但仔细研究之后,其实倒也不是什么大不了的工作。
如下代码:
#!/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 '----------------------------'
#p#分页标题#e#
运行功效:
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'] --------------------
#p#分页标题#e#
由于工具属性就算内容完全一样(刚初始化后的属性内容一般都是一样的),也会分派到完全差异的内存地点上去。所以不存在「同类工具之间影响」的环境。
但假如让一个工具的属性和另一个工具的属性指向同一个地点,两者之间(但也仅限两者之间)便又相互连累起来。