Heim  >  Artikel  >  Backend-Entwicklung  >  Referenzen und Klassenattribute in Python verstehen

Referenzen und Klassenattribute in Python verstehen

高洛峰
高洛峰Original
2016-10-18 09:56:29980Durchsuche

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.

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn