Heim > Artikel > Backend-Entwicklung > Referenzen und Klassenattribute in Python verstehen
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
Das laufende Ergebnis lautet wie folgt:
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
Dem „Ursprung“-Teil nach zu urteilen, sind die Adressen jedes Elements in der Liste genau 24 voneinander entfernt und verweisen nacheinander auf ihre jeweiligen Daten – das erinnert mich an ein Array.
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 nur 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 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'] ----------------------------
In „Origin“ sind die Adressen gleicher Klassenattribute von Objekten gleichen Typs und Unterklassenobjekten gleich – das ist das sogenannte „Sharing“.
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.
Daher muss „Klassenattribute beeinflussen sich gegenseitig zwischen derselben Klasse und ihren Unterklassen“ eine Voraussetzung haben: Nach der Erstellung der Instanz wurden ihre Klassenattribute nie neu zugewiesen, das heißt, die Klassenattribute verweisen immer noch darauf die ursprüngliche Speicheradresse.
Abschließend erwähnen wir noch die Objektattribute
Der folgende Code:
#!/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'] --------------------
Die Attributinhalte nach der Initialisierung sind im Allgemeinen gleich) und werden einem völlig anderen Speicher zugewiesen Adressen. Daher gibt es keinen „Einfluss zwischen ähnlichen Objekten“.
Aber wenn die Attribute eines Objekts und die Attribute eines anderen Objekts auf dieselbe Adresse verweisen, sind die beiden (aber nur zwischen den beiden) aneinander beteiligt.