Python是一种解释型、面向对象、动态数据类型的高级程序设计语言。自从20世纪90年代初Python语言诞生至今,它逐渐被广泛应用于处理系统管理任务和Web编程。Python已经成为最受欢迎的程序设计语言之一。2011年1月,它被TIOBE编程语言排行榜评为2010年度语言。自从2004年以后,python的使用率是呈线性增长。
Python在设计上坚持了清晰划一的风格,这使得Python成为一门易读、易维护,并且被大量用户所欢迎的、用途广泛的语言。
鉴于以上各种优点,忍不住对Python进行了一番学习,略有收获,分享给大家。
最近对Python 的对象引用机制稍微研究了一下,留下笔记,以供查阅。
首先有一点是明确的:「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
运行结果如下:
从「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 中类属性,有人提到过「类属性在同一类及其子类之间共享,修改类属性会影响到同一类及其子类的所有对象」。
听着挺吓人,但仔细研究之后,其实倒也不是什么大不了的事情。
如下代码:
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 'タレント変更後(リスト)'
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
印刷 '-------------------------------------'
# 新しいタレント ツリーに変更します (クラス属性全体を置き換えます)
bird.talent = ['swim']
print 'タレントの再割り当て後'
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 'タレントの再割り当て後の変更要素'
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 ' ----------------------------'
実行結果:
「Origin」では、同じ型のオブジェクトやサブクラスオブジェクトの同じクラス属性のアドレスが同じ、いわゆる「共有」です。
名前を変更すると、変更されたオブジェクトの name 属性のみが変更されます。これは、name への代入操作が実際には文字列を変更し、それを再引用しているためです。文字列自体は変更されていません。したがって、同じクラスとサブクラスの間には相互影響はありません。
次に、タレントの要素を変更します。この時点で状況が変わりました。同じクラスとそのサブクラスのタレント属性がすべて一緒に変更されました。これらはすべて同じメモリ アドレスと同じオブジェクトを参照しているため、これは理解しやすいです。
次に、タレントを再割り当てします。つまり、別のオブジェクトを参照するように変更します。その結果、このインスタンスのタレント属性のみが変更されます。メモリ アドレスから、このインスタンスと他のインスタンスのタレント属性が同じオブジェクトを指していないことがわかります。つまり、「この時点で、この例はすでに部外者である」ということです。
その後、最終的にタレントの要素を再度変更すると、他のインスタンスには影響がないことが簡単に理解できます。もう「部外者」だから、いくらいじっても、すべて自分のことだ。
したがって、「同じクラスとそのサブクラス間でクラス属性が相互に影響を与える」には前提条件が必要です。インスタンスの作成後、そのクラス属性は一度も再割り当てされていない、つまり、クラス属性は依然としてメモリアドレスを指しているということです。元々は を指していました。
最後に、オブジェクトのプロパティについて触れてみましょう
次のコード:
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 '属性変更後'
print id(bird.talent),bird.talent
print id(bird2.talent),bird2.talent
print '-------- ------------「
# Seek death: 2 つのオブジェクトの属性は同じメモリ アドレスを指し、
bird.talent =bird2.talent
bird.talent[0] = 'swim'
print '別の属性に割り当てて変更します'
print id(bird.talent),bird.talent
print id(bird2.talent),bird2.talent
print '---- ----------------'
実行結果:
オブジェクトの属性の内容が全く同じ(初期化直後の属性の内容は一般に同じ)であっても、全く異なるメモリアドレスに割り当てられるためです。したがって、「類似したオブジェクト間の影響」はありません。
しかし、あるオブジェクトの属性と別のオブジェクトの属性が同じアドレスを指している場合、その 2 つは (ただし 2 つの間でのみ) 相互に関係します。