Ich habe kürzlich ein wenig über den Objektreferenzmechanismus von Python recherchiert und Notizen als Referenz hinterlassen.
Zuallererst ist eines klar: „Alles in Python ist ein Objekt.“
Also, was bedeutet das?
Der folgende Code:
#!/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
Die laufenden Ergebnisse sind wie folgt:
PastgiftMacbookPro:python pastgift$ . /refTest.py
Ursprung
4299760200 [0, 1, 2]
4298181328 0
4298181304 1
4298181280 2
-------
nach Änderung a[0]
4299760200 [4, 1, 2]
4298181232 4
4298181304 1
4298181280 2
------------------ -------- -
nach Änderung a[1]
4299760200 [4, 5, 2]
4298181232 4
4298181208 5
4298181280 2
-----------------------------------
wie wäre es mit const 0?
4298181328 0
Aus dem „Ursprung“-Teil sind die Adressen jedes Elements in der Liste genau 24 unterschiedlich und verweisen wiederum auf ihre jeweiligen Daten - Das erinnert mich an Arrays.
Nachdem der Wert von a[0] geändert wurde, wurde festgestellt, dass sich die Adresse von a[0] geändert hat. Mit anderen Worten: Die Zuweisungsanweisung macht tatsächlich wieder einen [0]-Punkt auf ein anderes Objekt. Darüber hinaus wird auch darauf hingewiesen, dass sich die Adresse von a[0] und die Adresse von a[2] um 48 (zwei 24er) unterscheiden.
Wenn a[1] erneut geändert wird, ändert sich auch die Adresse von a[1]. Interessanterweise unterscheiden sich diesmal die Adresse von a[1] und die Adresse von a[0] um 24 72 (drei 24er) anders als das Original a[2].
Wenn schließlich die Adresse der Zahl 0 direkt gedruckt wird, stellt sich heraus, dass ihre Adresse genau mit der Adresse des ersten a[0] übereinstimmt.
An dieser Stelle lässt sich grundsätzlich erklären, dass es sich auch bei den Elementen in der Liste tatsächlich um Referenzen handelt. Durch das Ändern der Elemente in der Liste wird tatsächlich die Referenz geändert.
In Bezug auf Klassenattribute in Python erwähnte jemand, dass „Klassenattribute von derselben Klasse und ihren Unterklassen gemeinsam genutzt werden und dass sich die Änderung von Klassenattributen auf alle Objekte derselben Klasse und ihrer Unterklassen auswirkt.“
Es klingt beängstigend, aber nach sorgfältiger Untersuchung ist es keine so große Sache.
Der folgende Code:
#!/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 '----------------------------'
Laufergebnis:
PastgiftMacBookpro: Python Pastgift $ ./changeattributetest.py
Original Attr
4301998000 Bird
4301855 7352 ['FLY']
4301998000 Vogel
4301857352 ['fliegen']
4301998000 Vogel
4301857352 ['fliegen']
---- -- -----------------------
nach Namensänderung
4301986984 Vogelname geändert!
4301857352 [ 'fliegen']
4301998000 Vogel
4301857352 ['fliegen']
4301998000 Vogel
4301857352 ['fliegen']
--------------
nach Talentwechsel (eine Liste)
4301986984 Vogelname geändert!
4301857352 ['walk']
4301998000 Vogel
4301857352 ['walk']
4301998000 Vogel
43018 57352 [ 'walk']
------------------------------------------
nach Neuzuweisung Talent
4301986984 Vogelname geändert!
4301859512 ['schwimmen']
4301998000 Vogel
4301857352 ['laufen']
4301 998000 Vogel
4301857352 ['Spaziergang']
-------------------------------------------- -----
wechselndes Element nach Neuzuweisung des Talents
4301986984 Vogelname geändert!
4301859512 ['tanzen']
4301998000 Vogel
4301857352 ['Spaziergang']
4301998000 Vogel
4301857352 ['Spaziergang']
--------------- ----------- --
In „Origin“ sind die Adressen derselben Klassenattribute von Objekten desselben Typs und Unterklassenobjekten gleich – das ist das sogenannte „Teilen“.
Nach dem Ändern des Namens ändert sich nur das Namensattribut des geänderten Objekts. Dies liegt daran, dass bei der Zuweisungsoperation zu name tatsächlich eine Zeichenfolge geändert und in neue Anführungszeichen gesetzt wird. Die Zeichenfolge selbst hat sich nicht geändert. Daher gibt es keine gegenseitige Beeinflussung zwischen derselben Kategorie und Unterkategorien.
Als nächstes ändern Sie die Elemente im Talent. Zu diesem Zeitpunkt hat sich die Situation geändert: Die Talentattribute derselben Klasse und ihrer Unterklassen haben sich alle gemeinsam geändert. Dies ist leicht zu verstehen, da sie sich alle auf dieselbe Speicheradresse und dasselbe Objekt beziehen.
Als nächstes weisen Sie das Talent neu zu, d. h. ändern Sie es so, dass es auf ein anderes Objekt verweist. Das Ergebnis ist, dass sich nur das Talentattribut dieser Instanz ändert. Aus der Speicheradresse ist ersichtlich, dass die Talentattribute dieser Instanz und anderer Instanzen nicht mehr auf dasselbe Objekt verweisen. Das heißt: „Zu diesem Zeitpunkt ist dieses Beispiel bereits ein Außenseiter.“
Nachdem man dann endlich die Elemente im Talent erneut modifiziert hat, ist es leicht zu verstehen, dass es keine Auswirkungen auf andere Instanzen hat. Da ich bereits ein „Außenseiter“ bin, ist alles meine eigene Sache, egal wie sehr ich mich damit herumlege.
所以,「类属性在同类及其子类之间互相影响」必须有一个前提条件:实例建立后,其类属性从来没有被重新赋值过,即类属性依然指向最初所指向的内存地址。
最后提一下对象属性
如下代码:
#!/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']
--------------------
由于对象属性就算内容完全一样(刚初始化后的属性内容一般都是一样的),也会分配到完全不同的内存地址上去。所以不存在「同类对象之间影响」的情况。
但如果让一个对象的属性和另一个对象的属性指向同一个地址,两者之间(但也仅限两者之间)便又互相牵连起来。