Unter welchen Umständen haben gleiche Strings die gleiche Referenz?

Ich habe das Web durchsucht und Stapelüberlauf Fragen, aber nicht in der Lage, eine Antwort auf diese Frage zu finden. Die Beobachtung, die ich gemacht habe, ist, dass in Python 2.7.3, wenn Sie zwei Variablen die gleiche einzelne Zeichenfolge, zB

>>> a = 'a' >>> b = 'a' >>> c = ' ' >>> d = ' ' 

Dann teilen sich die Variablen dieselbe Referenz:

 >>> a is b True >>> c is d True 

Dies gilt auch für einige längere Saiten:

 >>> a = 'abc' >>> b = 'abc' >>> a is b True >>> ' ' is ' ' True >>> ' ' * 1 is ' ' * 1 True 

Allerdings gibt es eine Menge von Fällen, wo die Referenz ist (unerwartet) nicht geteilt:

 >>> a = 'ac' >>> b = 'ac' >>> a is b False >>> c = ' ' >>> d = ' ' >>> c is d False >>> ' ' * 2 is ' ' * 2 False 

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

Ich vermute, dass es vielleicht Vereinfachungen / Substitutionen des Dolmetschers und / oder eines Caching-Mechanismus gibt, der von der Tatsache Gebrauch macht, dass Python-Strings in einigen Sonderfällen unveränderlich sind, aber was weiß ich? Ich habe versucht, tiefe Exemplare von Strings mit dem Str-Konstruktor und der copy.deepcopy-Funktion zu machen, aber die Strings noch immer uneinheitlich teilen Referenzen.

Der Grund, warum ich Probleme damit habe, ist, weil ich auf Ungleichheit der Verweise auf Strings in einigen Unit-Tests Ich schreibe für Klon-Methoden der neuen Stil Python-Klassen zu überprüfen.

3 Solutions collect form web for “Unter welchen Umständen haben gleiche Strings die gleiche Referenz?”

Die Details, wann Strings zwischengespeichert und wiederverwendet werden, sind implementierungsabhängig, können von der Python-Version in die Python-Version wechseln und können sich nicht verlassen. Wenn Sie Strings für Gleichheit überprüfen möchten, verwenden Sie == , nicht is .

In CPython (die am häufigsten verwendete Python-Implementierung) werden String-Literale, die im Quellcode auftreten, immer interniert, also wenn das gleiche String-Literal zweimal im Quellcode auftritt, werden sie am Ende auf das gleiche String-Objekt zeigen. In Python 2.x kannst du auch die eingebaute Funktion intern() aufrufen, intern() zu erzwingen, dass ein bestimmter String interniert wird, aber das solltest du eigentlich nicht tun.

Bearbeiten Sie in Bezug auf Sie das eigentliche Ziel der Überprüfung, ob Attribute falsch zwischen Instanzen geteilt werden: Diese Art von Überprüfung ist nur für veränderliche Objekte nützlich. Für Attribute von unveränderlichem Typ gibt es keinen semantischen Unterschied zwischen geteilten und ungeteilten Objekten. Sie können unveränderliche Typen von Ihren Tests ausschließen

 Immutable = basestring, tuple, numbers.Number, frozenset # ... if not isinstance(x, Immutable): # Exclude types known to be immutable 

Beachten Sie, dass dies auch Tupel ausschließen würde, die veränderliche Objekte enthalten. Wenn du diese testen wolltest, musst du rekursiv in Tupel hinabsteigen.

In CPython wird als Implementierungsdetail die leere Zeichenfolge geteilt , ebenso Single-Character-Strings, deren Codepunkt im Latin-1-Bereich liegt. Du solltest nicht davon abhängen, da es möglich ist, diese Funktion zu umgehen.

Sie können einen String anfordern, der mit sys.intern interniert werden sys.intern . Dies geschieht in einigen Fällen automatisch:

Normalerweise werden die in Python-Programmen verwendeten Namen automatisch interniert, und die Wörterbücher, die verwendet werden, um Modul-, Klassen- oder Instanzattribute zu halten, haben internierte Schlüssel.

sys.intern ist so ausgesetzt, dass man sie nach der profilierung nutzen kann!

Interne Strings sind nützlich, um ein wenig Leistung auf Wörterbuch-Lookup zu gewinnen – wenn die Schlüssel in einem Wörterbuch interniert sind und der Lookup-Schlüssel interniert ist, können die Key-Vergleiche (nach dem Hashing) durch einen Zeigervergleich statt eines String-Vergleichs durchgeführt werden.

Beachten Sie, dass intern ein eingebettetes Python 2 ist.

Ich denke, es ist eine Implementierungs- und Optimierungssache. Wenn die Saite kurz ist, können sie (und sind oft?) "Geteilt", aber du kannst nicht davon abhängen. Sobald Sie längere Saiten haben, können Sie sehen, dass sie nicht gleich sind.

 In [2]: s1 = 'abc' In [3]: s2 = 'abc' In [4]: s1 is s2 Out[4]: True 

Längere Saiten

 In [5]: s1 = 'abc this is much longer' In [6]: s2 = 'abc this is much longer' In [7]: s1 is s2 Out[7]: False 

Verwenden Sie == , um Strings zu vergleichen (und nicht der Operator).

OPs Beobachtung / Hypothese (in den Kommentaren unten), dass dies auf die Anzahl der Token zurückzuführen sein scheint, wird durch die folgenden unterstützt:

 In [12]: s1 = 'abc' In [13]: s2 = 'abc' In [14]: s1 is s2 Out[14]: False 

Verglichen mit dem Anfangsbeispiel von abc oben.

  • Schrecklich, unveränderlich
  • Unerwartetes Verhalten von Extend mit einer Liste in Python
  • Python: Warum kann ich veränderliches Objekt in einen Dict oder Set setzen?
  • Warum können Tupel veränderliche Gegenstände enthalten?
  • Warum tupel in Python arbeiten mit umgekehrt aber nicht __reversed__?
  • Wie bekomme ich ein beliebiges Element aus einem Frozenset?
  • Warum sind Python-Strings und Tupel unveränderlich gemacht?
  • Was wäre ein "gefrorenes Dict"?
  • Das unveränderliche Objekt in Python
  • Was wäre ein "gefrorenes Dict"?
  • Python ist die beste Programmiersprache der Welt.