Objektmethoden derselben Klasse haben dieselbe ID?

8
%Vor%

Im obigen Code verstehe ich nicht, warum die nutzlose_func dieselbe ID hat, wenn sie zu zwei verschiedenen Objekten gehört?

    
iamkhush 24.05.2013, 04:02
quelle

2 Antworten

7

Hier ist was ich denke passiert:

  1. Wenn Sie p1.useless_func dereferenzieren, wird eine Kopie davon im Speicher erstellt. Dieser Speicherort wird von id zurückgegeben.
  2. Da es keine Verweise auf die Kopie der soeben erstellten Methode gibt, wird sie vom GC zurückgerufen und die Speicheradresse ist wieder verfügbar
  3. Wenn Sie p2.useless_func dereferenzieren, wird eine Kopie davon in derselben Speicheradresse erstellt (sie war verfügbar), die Sie mit id erneut abrufen.
  4. Die zweite Kopie ist GCd

Wenn Sie eine Menge anderen Code ausführen und die IDs der Instanzmethoden erneut überprüfen würden, wette ich, dass die id s identisch sind, sich aber vom ursprünglichen Lauf unterscheiden.

Außerdem können Sie bemerken, dass in David Wolvers Beispiel eine dauerhafte Referenz auf die Methodenkopie erhalten wird, die id s werden anders.

Um diese Theorie zu bestätigen, folgt hier eine Shell-Sitzung mit Jython (dasselbe Ergebnis mit PyPy), die CPythons Referenzzähler-Speicherbereinigung nicht verwendet:

%Vor%     
Asad Saeeduddin 24.05.2013, 04:22
quelle
11

Das ist eine sehr interessante Frage!

Unter Ihren Bedingungen erscheinen sie gleich:

%Vor%

Beachten Sie jedoch, dass wenn Sie etwas mit ihnen machen, sie anders werden:

%Vor%

Und dann, wenn sie erneut getestet werden, haben sie sich wieder verändert!

%Vor%

Wenn auf eine Methode für eine Instanz zugegriffen wird, wird eine Instanz der "gebundenen Methode" zurückgegeben. Eine gebundene Methode speichert einen Verweis auf die Instanz und auf das Funktionsobjekt der Methode:

%Vor%

(Beachten Sie, dass ich Foo.__dict__['method'] , nicht Foo.method verwenden muss, weil Foo.method eine "ungebundene Methode" ergibt ... deren Zweck dem Leser als Übung überlassen wird)

Der Zweck dieses Objekts "gebundene Methode" besteht darin, Methoden "sich sinnvoll zu verhalten", wenn sie wie Funktionen weitergegeben werden. Wenn ich zum Beispiel die Funktion a_m() aufruft, ist das identisch mit dem Aufruf von a.method() , obwohl wir keinen expliziten Verweis auf a mehr haben. Vergleichen Sie dieses Verhalten mit JavaScript (zum Beispiel), wobei var method = foo.method; method() nicht dasselbe Ergebnis liefert wie foo.method() .

SO! Dies bringt uns zurück zur ersten Frage: Warum scheint id(a.method) den gleichen Wert wie id(b.method) zu haben? Ich glaube, dass Asad richtig ist: es hat mit Python's zählendem Müllsammler zu tun *: wenn der Ausdruck id(a.method) ausgewertet wird, wird eine gebundene Methode zugewiesen, die ID berechnet und die gebundene Methode wird freigegeben. Wenn die nächste gebundene Methode - für b.method - zugewiesen wird, wird sie genau dem gleichen Speicherort im Speicher zugeordnet, da seit der gebundenen Methode für a.method keine (oder eine ausgeglichene Anzahl) Zuweisungen stattgefunden haben. wurde zugeteilt. Dies bedeutet, dass a.method den gleichen Speicherort hat wie b.method .

Schließlich erklärt dies, warum sich die Speicherplätze bei der zweiten Überprüfung scheinbar ändern: Die anderen Zuordnungen, die zwischen der ersten und der zweiten Überprüfung stattgefunden haben, bedeuten, dass sie beim zweiten Mal an einem anderen Ort zugewiesen werden ( Hinweis: Sie werden neu zugewiesen, weil alle Verweise auf sie verloren gegangen sind, gebundene Methoden werden zwischengespeichert †, dh, wenn Sie zweimal auf dieselbe Methode zugreifen, wird dieselbe Instanz zurückgegeben: a_m0 = a.method; a_m1 = a.method; a_m0 is a_m1 => True ).

*: Anmerkung der Pedanten: Eigentlich hat das nichts mit dem eigentlichen Müllsammler zu tun, der nur existiert, um mit zirkulären Referenzen umzugehen ... aber ... das ist eine Geschichte für einen anderen Tag.
†: zumindest in CPython 2.7; CPython 2.6 scheint gebundene Methoden nicht im Cache zu speichern, was mich zu der Annahme verleiten würde, dass das Verhalten nicht spezifiziert ist.

    
David Wolever 24.05.2013 04:14
quelle

Tags und Links