Dlaczego porównywanie łańcuchów za pomocą '= = ' lub 'is' czasami daje inny wynik?

Mam program w Pythonie, w którym dwie zmienne są ustawione na wartość 'public'. W wyrażeniu warunkowym mam porównanie var1 is var2, które się nie powiedzie, ale jeśli zmienię je na var1 == var2 zwraca True.

Teraz, jeśli otworzę mój interpreter Pythona i zrobię to samo porównanie "jest", to się powiedzie.

>>> s1 = 'public'
>>> s2 = 'public'
>>> s2 is s1
True

Co mi tu umyka?

Author: martineau, 2009-10-01

15 answers

is jest testowaniem tożsamości, {[2] } jest testowaniem równości. to, co dzieje się w Twoim kodzie, będzie emulowane w interpreterze w następujący sposób:

>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False
Więc nic dziwnego, że nie są takie same, prawda?

Innymi słowy: a is b jest odpowiednikiem id(a) == id(b)

 1577
Author: SilentGhost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-10 08:52:41

Inne odpowiedzi są poprawne: {[0] } jest używany do porównaniatożsamości , podczas gdy == jest używany do porównaniarówności . Ponieważ zależy ci na równości (oba łańcuchy powinny zawierać te same znaki), w tym przypadku operator is jest po prostu niewłaściwy i powinieneś używać ==.

Powodem, dla którego is działa interaktywnie, jest to, że (większość) literałów łańcuchowych jest domyślnie internowana . Z Wikipedii:

Interned strings speed up string porównania, które są czasem wąskie gardło wydajności w zastosowaniach (np. kompilatory i dynamiczne język programowania runtimes), które polegaj w dużym stopniu na tablicach hashowych z klucze strunowe. Bez stażu, sprawdzanie, że dwa różne ciągi są sobie równe. badając każdy znak obu łańcuchów. To jest powolny z kilku powodów: jest z natury O (n) w długości ciągów; zwykle wymaga odczytu z kilku regionów pamięci, które take czas; a lektury wypełniają pamięci podręcznej procesora, czyli jest mniej pamięć podręczna dostępna dla innych potrzeb. Z interned strings, a simple object test tożsamości wystarczy po oryginalna operacja stażysty; jest to zazwyczaj zaimplementowane jako wskaźnik test równości, zwykle tylko jeden Instrukcja maszynowa bez pamięci w ogóle.

Więc, gdy masz dwa literały łańcuchowe (słowa, które są dosłownie wpisane do kodu źródłowego programu, otoczone cudzysłów) w programie, który ma tę samą wartość, kompilator Pythona automatycznie intern ciągi znaków, dzięki czemu oba są przechowywane w tym samym miejscu pamięci. (Zauważ, że tak się nie dzieje Zawsze , a Zasady, kiedy tak się dzieje, są dość zawiłe, więc proszę, nie polegaj na tym zachowaniu w kodzie produkcyjnym!)

Ponieważ w sesji interaktywnej oba ciągi znaków są faktycznie przechowywane w tym samym miejscu pamięci, mają tę samą tożsamość , więc is operator działa zgodnie z oczekiwaniami. Ale jeśli skonstruujesz łańcuch za pomocą innej metody (nawet jeśli łańcuch zawiera dokładnie te same znaki), to łańcuch może być równy, ale nie jest to ten sam łańcuch -- to znaczy, że ma inną tożsamość, ponieważ jest przechowywany w innym miejscu w pamięci.

 598
Author: Daniel Pryden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-02 14:28:56

Słowo kluczowe is jest testem tożsamości obiektu, podczas gdy {[1] } jest porównaniem wartości.

Jeśli użyjesz is, wynik będzie prawdziwy wtedy i tylko wtedy, gdy obiekt jest tym samym obiektem. Jednak == będzie prawdziwe za każdym razem, gdy wartości obiektu są takie same.

 109
Author: Thomas Owens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-01 15:45:02

Jeszcze jedna uwaga, możesz użyć sys.intern funkcja zapewniająca uzyskanie odniesienia do tego samego ciągu znaków:

>>> from sys import intern
>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True

Jak wspomniano powyżej, nie należy używać is do określania równości łańcuchów. Ale może to być pomocne, aby wiedzieć, jeśli masz jakieś dziwne wymagania, aby użyć is.

Zauważ, że funkcja intern była wbudowana w Pythona 2, ale została przeniesiona do modułu sys w Pythonie 3.

 58
Author: Jason Baker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-16 15:43:18

is jest testowaniem tożsamości i {[2] } jest testowaniem równości. Oznacza to, że {[1] } jest sposobem sprawdzenia, czy dwie rzeczy są tymi samymi rzeczami, czy tylko równoważnymi.

Powiedz, że masz prosty person obiekt. Jeśli nazywa się "Jack" i ma 23 lata, jest odpowiednikiem innego 23-letniego Jacka, ale nie jest to ta sama osoba.

class Person(object):
   def __init__(self, name, age):
       self.name = name
       self.age = age

   def __eq__(self, other):
       return self.name == other.name and self.age == other.age

jack1 = Person('Jack', 23)
jack2 = Person('Jack', 23)

jack1 == jack2 # True
jack1 is jack2 # False
Są w tym samym wieku, ale nie są tą samą osobą. Łańcuch może być odpowiednikiem innego, ale nie jest to ten sam obiekt.
 45
Author: TankorSmash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-01 09:24:22

Jest to poboczna uwaga, ale w Pythonie idiomatycznym często można zobaczyć takie rzeczy jak:

if x is None:
    # Some clauses

Jest to bezpieczne, ponieważ jest gwarantowana jedna instancja obiektu Null (None).

 37
Author: Gregg Lind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-01 09:22:05

Jeśli nie jesteś pewien, co robisz, użyj'=='. Jeśli masz trochę więcej wiedzy na ten temat, możesz użyć 'is' dla znanych obiektów, takich jak'None'.

W przeciwnym razie będziesz się zastanawiać, dlaczego rzeczy nie działają i dlaczego tak się dzieje:

>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False

Nie jestem nawet pewien, czy pewne rzeczy mają gwarancję, że pozostaną takie same pomiędzy różnymi wersjami/implementacjami Pythona.

 28
Author: Mattias Nilsson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-01 16:57:09

Z mojego ograniczonego doświadczenia z Pythonem, is jest używany do porównywania dwóch obiektów, aby sprawdzić, czy są one tym samym obiektem, w przeciwieństwie do dwóch różnych obiektów o tej samej wartości. == jest używany do określenia, czy wartości są identyczne.

Oto dobry przykład:

>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True

s1 jest ciągiem unicode, a s2 jest ciągiem normalnym. Nie są one tego samego typu, ale są tej samej wartości.

 22
Author: Jack M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-01 20:04:28

Myślę, że ma to związek z faktem, że gdy porównanie 'is' jest obliczane na false, używane są dwa różne obiekty. Jeśli obliczy wartość true, oznacza to, że wewnętrznie używa tego samego obiektu i nie tworzy nowego, prawdopodobnie dlatego, że utworzyłeś je w ciągu ułamka 2 sekund lub więcej i ponieważ nie ma dużej przerwy czasowej między zoptymalizowanym i używającym tego samego obiektu.

Dlatego powinieneś używać operatora równości ==, a nie is, aby porównać wartość obiektu string.

>>> s = 'one'
>>> s2 = 'two'
>>> s is s2
False
>>> s2 = s2.replace('two', 'one')
>>> s2
'one'
>>> s2 is s
False
>>> 

W tym przykładzie stworzyłem s2, który był innym obiektem typu string, wcześniej równym "one", ale nie jest to ten sam obiekt co s, ponieważ interpreter nie używał tego samego obiektu, ponieważ nie przypisałem go początkowo do "one", gdybym miał, zrobiłby z nich ten sam obiekt.

 18
Author: meder omuraliev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-01 15:54:20

Uważam, że jest to znane jako "internowane" ciągi. Python robi to, podobnie jak Java, a także C i C++ podczas kompilacji w trybach zoptymalizowanych.

Jeśli używasz dwóch identycznych łańcuchów, zamiast marnować pamięć przez tworzenie dwóch obiektów łańcuchowych, wszystkie internowane łańcuchy o tej samej zawartości wskazują na tę samą pamięć.

Powoduje to, że Operator Pythona" is " zwraca True, ponieważ dwa łańcuchy o tej samej zawartości wskazują na ten sam obiekt string. Stanie się to również w Javie oraz w C.

Jest to przydatne tylko do oszczędzania pamięci. Nie można na niej polegać w testowaniu równości ciągów znaków, ponieważ różne Interpretatory i kompilatory oraz silniki JIT nie zawsze to robią.

 14
Author: Zan Lynx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-01 15:59:38

W rzeczywistości operator is sprawdza tożsamość i = = operator sprawdza równość.

z odniesień językowych:

Typy wpływają na prawie wszystkie aspekty zachowania obiektu. Nawet znaczenie tożsamości obiektu jest w pewnym sensie naruszone: dla typów niezmiennych operacje , które obliczają nowe wartości, mogą faktycznie zwrócić odniesienie do dowolnego istniejącego obiektu o tym samym typie i wartości, podczas gdy dla obiektów zmiennych nie jest to dozwolone. Np. po = 1; b = 1, a i b mogą odnosić się lub nie do tego samego obiektu o wartości one, w zależności od implementacji, ale po c = []; d = [], C i D mają zagwarantowane odnosić się do dwóch różnych, unikalnych, nowo utworzonych pustych list. (Zauważ, że c = d = [] przypisuje ten sam obiekt zarówno c jak i d.)

Tak więc z powyższego stwierdzenia możemy wywnioskować, że ciągi znaków, które są typami niezmiennymi, mogą się nie udać, gdy są zaznaczone za pomocą" is "i mogą się udać, gdy są zaznaczone za pomocą"is".

To samo dotyczy int i tuple, które również są typami niezmiennymi.

 13
Author: Ram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-01 09:27:00

Operator == sprawdza równoważność wartości. Operator is testuje tożsamość obiektu, a Python sprawdza, czy oba te obiekty są rzeczywiście tymi samymi obiektami (np. żyją pod tym samym adresem w pamięci).

>>> a = 'banana'
>>> b = 'banana'
>>> a is b
True

W tym przykładzie Python stworzył tylko jeden obiekt string i zarówno a, jak i b odnoszą się do niego. Powodem jest to, że Python wewnętrznie buforuje i ponownie wykorzystuje niektóre ciągi jako optymalizację. W pamięci jest tylko ciąg "banana", dzielony przez a i b. aby wyzwolić normalne zachowanie, trzeba użyć dłuższych ciągów:

>>> a = 'a longer banana'
>>> b = 'a longer banana'
>>> a == b, a is b
(True, False)

Kiedy tworzysz dwie listy, otrzymujesz dwa obiekty:

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a is b
False

W tym przypadku powiedzielibyśmy, że obie listy są równoważne, ponieważ mają te same elementy, ale nie są identyczne, ponieważ nie są tym samym obiektem. Jeśli dwa obiekty są identyczne, to również są równoważne, ale jeśli są równoważne, niekoniecznie są identyczne.

Jeśli a odnosi się do obiektu i przypisujesz b = a, to obie zmienne odnoszą się do ten sam obiekt:

>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
 9
Author: X. Wang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-01 09:29:53

is porównuje lokalizację pamięci. Służy do porównywania na poziomie obiektów.

== porównuje zmienne w programie. Służy do sprawdzania na poziomie wartości.

is sprawdzanie równoważności poziomu adresu

== sprawdzanie równoważności poziomu wartości

 7
Author: johnashu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-16 08:15:49

is jest testowaniem tożsamości i == jest testowaniem równości (zobacz dokumentacja Pythona ).

W większości przypadków, jeśli a is b, to a == b. Ale są wyjątki, na przykład:

>>> nan = float('nan')
>>> nan is nan
True
>>> nan == nan
False

Więc możesz używać tylko is do testów tożsamości, nigdy testów równości.

 3
Author: Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-01 09:28:15

Podstawowe pojęcie, które musimy być jasne, gdy podchodzimy do tego pytania, to zrozumienie różnicy między jest i ==.

"is" porównuje lokalizację pamięci. if id (a)= = id (b), then a is b zwraca true w przeciwnym razie zwraca false.

Możemy więc powiedzieć, że is służy do porównywania lokalizacji pamięci.

== jest używany do testowania równości, co oznacza, że porównuje tylko wartości wynikowe. Poniżej pokazany kod może posłużyć jako przykład do powyższej teorii.

Kod

Kliknij tutaj, aby uzyskać kod

W przypadku literałów łańcuchowych(łańcuchów bez przypisania do zmiennych), adres pamięci będzie taki sam, jak pokazano na rysunku. ID (a)= = id (b). pozostaje to oczywiste.

 0
Author: praveen kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-26 17:04:52