Unter welchen Umständen teilen sich gleiche Zeichenketten die gleiche Referenz?

9

Ich habe die Web- und Stack-Überlauffragen durchsucht, konnte aber keine Antwort auf diese Frage finden. Die Beobachtung, die ich gemacht habe, ist die in Python 2.7.3, wenn Sie zwei Variablen die gleiche einzelne Zeichenfolge zuweisen, z. B.

%Vor%

Dann teilen sich die Variablen die gleiche Referenz:

%Vor%

Dies gilt auch für längere Strings:

%Vor%

Es gibt jedoch viele Fälle, in denen die Referenz (nicht zu erwarten) nicht geteilt wird:

%Vor%

Kann jemand bitte den Grund dafür erklären?

Ich vermute, es könnte Vereinfachungen / Ersetzungen durch den Interpreter und / oder einen Caching-Mechanismus geben, der die Tatsache nutzt, dass Python-Strings in einigen speziellen Fällen unveränderlich sind, um zu optimieren, aber was weiß ich? Ich habe versucht, tiefe Kopien von Strings mit dem str-Konstruktor und der Funktion copy.deepcopy zu erstellen, aber die Strings teilen immer noch Referenzen inkonsistent.

Der Grund, warum ich Probleme damit habe, liegt darin, dass ich in einigen Komponententests, die ich für Klon-Methoden von Python-Klassen neuen Stils schreibe, nach Ungleichheit der Verweise auf Strings suche.

    
EriF89 23.07.2012, 11:35
quelle

3 Antworten

8

Die Details darüber, wann Strings zwischengespeichert und wiederverwendet werden, sind implementierungsabhängig, können sich von Python-Version zu Python-Version ändern und sind nicht zuverlässig. Wenn Sie Zeichenfolgen auf Gleichheit überprüfen möchten, verwenden Sie == , nicht is .

In CPython (der am häufigsten verwendeten Python-Implementierung) werden String-Literale, die im Quellcode vorkommen, immer interniert. Wenn also das gleiche String-Literal zweimal im Quellcode auftritt, verweisen sie auf dasselbe String-Objekt . In Python 2.x können Sie auch die integrierte Funktion intern() aufrufen, um zu erzwingen dass eine bestimmte Zeichenfolge interniert ist, aber Sie sollten dies eigentlich nicht tun.

Bearbeiten in Bezug auf Ihr tatsächliches Ziel, zu überprüfen, ob Attribute zwischen Instanzen falsch geteilt werden: Diese Art von Prüfung ist nur für veränderbare Objekte nützlich. Für Attribute des unveränderlichen Typs gibt es keinen semantischen Unterschied zwischen freigegebenen und nicht gemeinsam genutzten Objekten. Sie können unveränderliche Typen von Ihren Tests ausschließen, indem Sie

verwenden %Vor%

Beachten Sie, dass dadurch auch Tupel ausgeschlossen werden, die veränderbare Objekte enthalten. Wenn Sie diese testen möchten, müssen Sie rekursiv in Tupel absteigen.

    
Sven Marnach 23.07.2012, 11:37
quelle
5

In CPython wird als Implementierungsdetail die leere Zeichenfolge gemeinsam verwendet . ebenso wie Zeichenfolgen mit einem Zeichen, deren Codepunkt im Latin-1-Bereich liegt. Sie sollten nicht davon abhängen, da es möglich ist, diese Funktion zu umgehen.

Sie können eine Zeichenfolge anfordern, die interniert sein soll, indem Sie sys.intern verwenden. ; Dies geschieht in einigen Fällen automatisch:

  

Normalerweise werden die in Python-Programmen verwendeten Namen automatisch interniert, und die Wörterbücher, die für Modul-, Klassen- oder Instanzattribute verwendet werden, haben interne Schlüssel.

sys.intern ist verfügbar, so dass Sie es (nach dem Profiling!) für die Leistung verwenden können:

  

Das Internieren von Strings ist nützlich, um bei der Wörterbuchsuche etwas Leistung zu erzielen. Wenn die Schlüssel in einem Wörterbuch interniert sind und der Suchschlüssel interniert ist, können die Schlüsselvergleiche (nach dem Hashing) durch einen Zeigervergleich anstelle einer Zeichenfolge durchgeführt werden vergleichen.

Beachten Sie, dass intern in Python 2 integriert ist.

    
ecatmur 23.07.2012 11:53
quelle
4

Ich denke, es ist eine Implementierung und Optimierung Sache. Wenn die Zeichenfolge kurz ist, können (und werden sie oft?) "Geteilt" werden, aber Sie können sich nicht darauf verlassen. Sobald Sie längere Zeichenfolgen haben, können Sie sehen, dass sie nicht gleich sind.

%Vor%

längere Strings

%Vor%

Verwenden Sie == , um Zeichenfolgen zu vergleichen (und nicht den Operator is ).

-

Die Beobachtung / Hypothese von OP (in den Kommentaren unten), dass dies auf die Anzahl der Token zurückzuführen sein könnte, scheint durch Folgendes zu unterstützen:

%Vor%

wenn mit dem anfänglichen Beispiel von abc oben verglichen.

    
Levon 23.07.2012 11:38
quelle