2010-06-07 14 views
52

... das Schlüsselwort is, das für die Gleichheit in Strings verwendet werden kann.Wie ist das Schlüsselwort 'is' in Python implementiert?

>>> s = 'str' 
>>> s is 'str' 
True 
>>> s is 'st' 
False 

habe ich versucht, sowohl __is__() und __eq__() aber sie funktionierte nicht.

>>> class MyString: 
... def __init__(self): 
...  self.s = 'string' 
... def __is__(self, s): 
...  return self.s == s 
... 
>>> 
>>> 
>>> m = MyString() 
>>> m is 'ss' 
False 
>>> m is 'string' # <--- Expected to work 
False 
>>> 
>>> class MyString: 
... def __init__(self): 
...  self.s = 'string' 
... def __eq__(self, s): 
...  return self.s == s 
... 
>>> 
>>> m = MyString() 
>>> m is 'ss' 
False 
>>> m is 'string' # <--- Expected to work, but again failed 
False 
>>> 

Antwort

107

Das Testen von Strings mit is funktioniert nur, wenn die Strings interniert sind. Sofern Sie nicht wirklich wissen, was Sie tun und explizit interned die Zeichenfolgen sollten Sie nie verwenden Sie is auf Strings.

is Tests für Identität, nicht Gleichheit. Das bedeutet, Python vergleicht einfach die Speicheradresse, in der sich ein Objekt befindet. is beantwortet im Grunde die Frage "Habe ich zwei Namen für das gleiche Objekt?" - Überladung, die keinen Sinn ergeben würde.

Zum Beispiel ist ("a" * 100) is ("a" * 100)False. Üblicherweise schreibt Python jeden String in einen anderen Speicherort, Interning geschieht meist für String-Literale.

+8

ich in der Vergangenheit beobachtet haben, dass Zeichenfolge Internierung für Laufzeit passieren kann berechnet und Eingabewerte, wenn sie ausreichend kurz sind. 'a' * 100 ist nicht 'a' * 100; aber 'a' * 20 ist "a" * 20. In der Zwischenzeit ist 'a'.upper() nicht' a'.upper(). Jython, IronPython, PyPy und andere können aggressiver arbeiten. Kurz gesagt ist es abhängig von der Implementierung. Wenn Sie die 'intern()' - Funktion für Strings aufrufen, wird "erzwungen", dass eine Zeichenkette die gleiche Objektidentität wie jede äquivalente und zuvor intern() 'd Zeichenkette hat, wie Sie sagen. Ich kenne jedoch keinen gültigen Anwendungsfall zum Testen der Zeichenfolgenidentität. (Mögliche Leistung beiseite). –

8

Das Schlüsselwort is vergleicht Objekte (oder vergleicht sie, wenn zwei Referenzen auf dasselbe Objekt verweisen).

Welches ist, denke ich, warum es keinen Mechanismus gibt, um Ihre eigene Implementierung zur Verfügung zu stellen.

Es passiert manchmal mit Strings, weil Python Strings "clever" speichert, so dass beim Erstellen von zwei identischen Strings sie in einem Objekt gespeichert werden.

>>> a = "string" 
>>> b = "string" 
>>> a is b 
True 
>>> c = "str"+"ing" 
>>> a is c 
True 

Sie können hoffentlich die Referenz vs Datenvergleich in einem einfachen 'Kopie' Beispiel sehen:

>>> a = {"a":1} 
>>> b = a 
>>> c = a.copy() 
>>> a is b 
True 
>>> a is c 
False 
17

Der is Operator Vergleich id(x) Werte entspricht. id wird derzeit implementiert, um Zeiger als Vergleich zu verwenden. Sie können also is nicht selbst überlasten, und AFAIK können Sie auch nicht überladen id.

So können Sie nicht. Ungewöhnlich in Python, aber da ist es.

+1

Sie können 'ID' überladen, aber nicht in dem Sinn, den Sie wahrscheinlich meinten. Tun Sie einfach "id = ". – HyperNeutrino

13

Das Schlüsselwort Python is testet die Objektidentität. Sie sollten es NICHT benutzen, um auf Gleichheit der Zeichenfolgen zu prüfen. Es scheint, dass es häufig funktioniert, weil Python-Implementierungen, wie die vieler sehr hoher Programmiersprachen, das "Interning" von Strings durchführen. Das bedeutet, dass Zeichenfolgenliterale und -werte intern in einer Hash-Liste gespeichert werden und die identischen Elemente als Referenzen auf dasselbe Objekt gerendert werden. (Dies ist möglich, weil Python-Strings unveränderlich sind).

Wie bei jedem Implementierungsdetail sollten Sie sich jedoch nicht darauf verlassen. Wenn Sie auf Gleichheit prüfen möchten, verwenden Sie den Operator ==. Wenn Sie wirklich auf Objektidentität prüfen möchten, dann verwenden Sie is --- und ich würde hart gedrängt werden, mit einem Fall zu kommen, in dem Sie sich um die Identität des String-Objekts kümmern sollten. Leider kann man nicht darauf zählen, ob zwei Strings aufgrund des erwähnten Praktikums irgendwie "absichtlich" identische Objektreferenzen sind.

+0

Der einzige Ort in Python, an dem Sie einen Identitätsvergleich durchführen möchten, ist der Vergleich mit Singletons (z. B. None) und Sentinel-Werten, die eindeutig sein müssen. Ansonsten gibt es wahrscheinlich fast keinen Grund dafür. –

+2

@Lie Ryan: Ich stimme dem zu. Ich benutze es nur für None und für spezielle Sentinels, die ich erstellt habe (normalerweise als Aufrufe an die Basis 'object()'). Ich fühle mich jedoch nicht wohl, wenn ich behaupte, dass es für den "Ist" -Operator keine anderen gültigen Verwendungen gibt; einfach keiner, an den ich denken kann. (Möglicherweise ein Beweis für meine eigene Ignoranz). –

5

Wenn Sie keine Angst haben, mit Bytecode zu vermasseln, können Sie COMPARE_OP mit 8 ("is") Argument abfangen und patchen, um Ihre Hook-Funktion auf Objekte, die verglichen werden, aufzurufen. Sehen Sie sich dis Modul Dokumentation für Start-in.

Und vergessen Sie nicht, __builtin__.id() auch abzufangen, wenn jemand id(a) == id(b) statt a is b tun wird.

+1

Interessant zu wissen, das ist eine ganze Welt von Möglichkeiten, sich mit der Funktion von Python zu messen, an die ich nie gedacht hätte. Aber warum sollte das eine gute Idee sein? – alexis

+0

In meiner Firma haben wir eine interne Testbibliothek, die einen Kontext-Decorator enthält, der die Zeit einfriert, indem er datetime.datetime durch eine Implementierung ersetzt, die immer eine bestimmte Zeit von utcnow() zurückgibt. Wenn Sie datetime.datetime.utcnow() ausführen und versuchen, den zurückgegebenen Wert zu pickle, wird es fehlschlagen, weil seine Klasse inkonsistent ist (es vorgibt, eine andere Klasse zu sein). In diesem Fall könnte das Überschreiben der Funktionsweise von "ist" eine Lösung sein. –

2

ist es nicht möglich, eine String-Variable mit einem String-Wert und zwei String-Variablen zu vergleichen, wenn der String mit '-' beginnt. Meine Python-Version ist 2.6.6

>>> s = '-hi' 
>>> s is '-hi' 
False 
>>> s = '-hi' 
>>> k = '-hi' 
>>> s is k 
False 
>>> '-hi' is '-hi' 
True 
1

Sie nicht den is Betreiber überlasten. Was Sie überlasten möchten, ist der Operator ==. Dies kann durch Definieren einer __eq__ Methode in der Klasse erfolgen.

1

Sie verwenden einen Identitätsvergleich. == ist wahrscheinlich, was Sie wollen. Die Ausnahme ist, wenn Sie überprüfen möchten, ob ein Objekt und ein anderes das GENAUE gleiche Objekt und an der gleichen Speicherposition sind. In Ihren Beispielen sind die Elemente nicht identisch, da eines von einem anderen Typ ist (my_string) als das andere (string). Auch gibt es keine Klasse. __is__ in Python (es sei denn natürlich, du hast es selbst dort). Wenn das der Fall wäre, wäre das Vergleichen von Objekten mit nicht zuverlässig, um einfach die Speicherorte zu vergleichen.

Als ich zum ersten Mal auf das Stichwort stieß, verwirrte es mich auch. Ich hätte gedacht, dass ist und == waren nicht anders. Sie erzeugten die gleiche Ausgabe vom Interpreter für viele Objekte. Diese Art der Annahme ist eigentlich genau was ist ... ist für. Es ist das Python-Äquivalent "Hey, verwechselt diese beiden Objekte nicht. Sie sind anders.", Was im Wesentlichen das ist, [wer immer es war, der mich auseinandernahm]. Anders formuliert, aber ein Punkt == der andere Punkt.

der für einige hilfreiche Beispiele und etwas Text mit den manchmal verwirrenden Unterschiede Besuch a document from python.org's mail host geschrieben von „Danny Yoo“

oder zu helfen, wenn diese offline ist, die unlisted pastebin verwende ich davon Körper gemacht.

, falls sie in etwa 20 oder so blau Monde (blau Monde ein reales Ereignis ist), sind beide nach unten, werde ich die Beispiele Code zitiere

### 
>>> my_name = "danny" 
>>> your_name = "ian" 
>>> my_name == your_name 
0    #or False 
### 

### 
>>> my_name[1:3] == your_name[1:3] 
1 #or True 
### 

### 
>>> my_name[1:3] is your_name[1:3] 
0 
### 
0

Assertion Fehler entstehen können leicht mit ist Schlüsselwort beim Vergleichen von Objekten. Zum Beispiel können die Objekte a und b denselben Wert haben und dieselbe Speicheradresse teilen.Deshalb tut ein

>>> a == b 

zu

True 

bewerten wird, aber wenn

>>> a is b 

zu

wertet
False 

sollten Sie vielleicht überprüfen

>>> type(a) 

und

>>> type(b) 

Diese könnten anders und ein Grund für das Scheitern sein.

1

'ist' vergleicht Objektidentität, während == Werte vergleicht.

Beispiel:

a=[1,2] 
b=[1,2] 
#a==b returns True 
#a is b returns False 

p=q=[1,2] 
#p==q returns True 
#p is q returns True