'=='또는 'is'를 사용하여 문자열을 비교하면 때때로 다른 결과가 생성되는 이유는 무엇입니까?


1146

두 개의 변수가 value로 설정된 Python 프로그램이 있습니다 'public'. 조건부 표현식에서는 비교 var1 is var2에 실패하지만 변경하면을 var1 == var2반환합니다 True.

이제 파이썬 인터프리터를 열고 동일한 "is"비교를 수행하면 성공합니다.

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

내가 여기서 무엇을 놓치고 있습니까?


8

3
이 문제는 다음을 통해 콘솔 입력을 읽을 때도 발생합니다 input = raw_input("Decide (y/n): "). 이 경우 "y"의 입력은 if input == 'y':"True"를 if input is 'y':반환하고 False는 반환합니다.
Semjon Mössinger

4
이 블로그는 어떤 대답보다 훨씬 더 완벽한 설명이 제공 guilload.com/python-string-interning
Chris_Rands

1
크리스 - 리코는 여기, 내가 좋은 설명을 언급 @으로 stackoverflow.com/q/15541404/1695680
ThorSummoner

답변:


1533

is신원 테스트, ==평등 테스트입니다. 코드에서 발생하는 일은 다음과 같이 인터프리터에서 에뮬레이트됩니다.

>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False

그들이 같지 않은 것도 당연합니다.

즉 : is는 ISid(a) == id(b)


17
아 EQ와 같나요? 대 동등? 계획에서, 그것을 얻었다.
jottos 09 년

47
또는 Java에서 ==vs. .equals()가장 좋은 점은 파이썬 ==이 자바와 유사하지 않다는 것 ==입니다.
MatrixFrog

11
@ Крайст : 단일 None값만 있습니다. 따라서 항상 같은 ID를 갖습니다.
SilentGhost

18
이것은 OP의 "is-> True"예제를 다루지 않습니다.
user2864740

6
문자열 interning 때문에 @AlexanderSupertramp .
Chris Rico

569

: 여기에 다른 대답이 올바른지 is에 사용되는 신원 반면, 비교 ==에 사용되는 평등의 비교. 당신이 신경 쓰는 것은 평등 (두 문자열은 같은 문자를 포함해야 함)이기 때문에이 경우 is연산자는 단순히 틀리므로 ==대신 사용해야합니다 .

is대화식으로 작동 하는 이유 는 (대부분의) 문자열 리터럴이 기본적 으로 포함 되기 때문입니다. Wikipedia에서 :

내부 문자열은 문자열 비교 속도를 높이며, 때로는 문자열 키가있는 해시 테이블에 의존하는 응용 프로그램 (예 : 컴파일러 및 동적 프로그래밍 언어 런타임)의 성능 병목 현상이 발생합니다. 인턴없이 두 개의 서로 다른 문자열이 같은지 확인하려면 두 문자열의 모든 문자를 검사해야합니다. 여러 가지 이유로 느립니다. 문자열 길이가 본질적으로 O (n)입니다. 일반적으로 여러 메모리 영역에서 읽기가 필요하며 시간이 걸립니다. 읽기는 프로세서 캐시를 채우므로 다른 요구에 사용할 수있는 캐시가 줄어 듭니다. 인턴 된 문자열을 사용하면 원래 인턴 작업 후에 간단한 객체 식별 테스트로 충분합니다. 이것은 일반적으로 포인터 평등 테스트로 구현됩니다.

따라서 동일한 값을 가진 프로그램에 두 개의 문자열 리터럴 (문자 그대로 프로그램 소스 코드에 따옴표로 묶은 단어)이 있으면 파이썬 컴파일러는 자동으로 문자열을 인턴하여 문자열을 동일하게 저장합니다 메모리 위치. ( 항상 이러한 상황이 발생하는 것은 아니며 이러한 상황이 발생하는 규칙은 매우 복잡하므로 프로덕션 코드에서이 동작에 의존하지 마십시오!)

대화식 세션에서 두 문자열은 실제로 동일한 메모리 위치에 저장 되므로 동일한 ID 를 가지므로 is연산자는 예상대로 작동합니다. 그러나 다른 방법으로 문자열을 구성하면 (문자열에 정확히 동일한 문자 가 포함되어 있더라도 ) 문자열은 같을 수 있지만 같은 문자열 이 아닙니다 . 즉, 다른 ID 를 가지므로 메모리의 다른 장소에 저장됩니다.


6
문자열이 삽입 될 때 복잡한 규칙에 대한 자세한 내용은 어디에서 볼 수 있습니까?
녹 티스 스카이 타워

88
자세한 설명을 보려면 +1 실제로 어떤 일이 일어 났는지 설명하지 않고 다른 답변이 어떻게 많은 투표를 받았는지 확실하지 않습니다.
That1Guy

4
이것이 제가 질문을 읽을 때 생각했던 것과 정확히 같습니다. 받아 들여지는 대답은 짧지 만 사실을 포함하지만이 대답은 훨씬 더 나은 것을 설명합니다 . 좋은!
Sнаđошƒӽ ӽ

3
@NoctisSkytower 봤는 같은과이 발견 guilload.com/python-string-interning
xtreak

5
@ naught101 : 아니, 규칙 사이에 선택하는 것입니다 ==is종류 확인의 당신이 원하는 무엇을 기반으로합니다. 문자열이 같거나 (같은 내용을 갖는) 신경이 쓰이는 경우 항상을 사용해야 ==합니다. 두 개의 파이썬 이름이 동일한 객체 인스턴스를 참조하는지 여부에 관심이 있다면를 사용해야합니다 is. 당신은해야 할 수도 있습니다 is그 내용에 대한 배려없이 다른 값의 핸들 많이, 또는 다른 무언가의 하나가 알고 있다면 당신은 그 일 척 다른 개체를 무시하려는 경우 당신에게있는 거 코드를 작성. 확실하지 않은 경우 항상을 선택하십시오 ==.
Daniel Pryden

108

is동안 키워드는 개체 식별을위한 테스트입니다 ==값 비교입니다.

을 사용 is하면 객체가 동일한 객체 인 경우에만 결과가 적용됩니다. 그러나 ==개체의 값이 같을 때마다 적용됩니다.


57

마지막으로 주목해야 할 것은 sys.intern함수를 사용 하여 동일한 문자열에 대한 참조를 얻는 것입니다.

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

위에서 지적했듯이 is문자열의 동등성을 결정 하는 데 사용해서는 안됩니다 . 그러나 이것은 당신이 어떤 이상한 요구 사항을 가지고 있는지 아는 데 도움이 될 수 있습니다 is.

점을 유의 intern함수 파이썬 (2)에 내장되도록 사용되지만 이동되었다 sys파이썬 3 모듈.


43

is신원 테스트, ==평등 테스트입니다. 이것이 의미하는 바 is는 두 가지가 같은 것이거나 동등한 지 여부를 확인하는 방법 입니다.

간단한 person물건 이 있다고 가정 해보십시오 . 이름이 '잭'이고 '23'년 된 경우 다른 23 세의 잭과 동일하지만 같은 사람이 아닙니다.

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

그들은 같은 나이이지만 같은 사람이 아닙니다. 문자열은 다른 문자열과 동일 할 수 있지만 동일한 개체가 아닙니다.


set을 변경해도 변경 jack1.age = 99되지 않습니다 jack2.age. 두 개의 서로 다른 인스턴스이기 때문 jack1 is not jack2입니다. 그러나 jack1 == jack2이름과 나이가 같으면 서로 동등 할 수 있습니다 . 파이썬에서는 문자열을 변경할 수 없으며 파이썬은 종종 같은 인스턴스를 재사용하기 때문에 문자열이 더 복잡해집니다. 나는이 설명이 특별한 경우 (문자열) 대신 간단한 경우 (일반 객체)를 사용하기 때문에 좋아합니다.
Flimm

37

이것은 부수적이지만 관용적 파이썬에서는 다음과 같은 것을 종종 볼 수 있습니다.

if x is None: 
    # some clauses

Null Object의 인스턴스 (즉, None)가 하나 보장 되므로 안전 합니다.


1
True와 False도 마찬가지입니까? 하나의 인스턴스 만 일치합니까?
HandyManDan

1
예 @HandyManDan, 그들은 파이썬 2와 3에서 싱글 모두
kamillitw

@kamillitw 그러나 Python 2에서는 False와 True를 다시 할당 할 수 있습니다.
Martijn Pieters

28

무엇을하고 있는지 잘 모르겠 으면 '=='를 사용하십시오. 그것에 대해 조금 더 알고 있다면 '없음'과 같은 알려진 객체에 'is'를 사용할 수 있습니다.

그렇지 않으면 왜 작동하지 않는지, 왜 이런 일이 발생하는지 궁금해 할 것입니다.

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

다른 파이썬 버전 / 구현 사이에서 동일한 것이 유지되는지 확실하지 않습니다.


1
int를 재 할당하는 방법을 보여주는 재미있는 예제가이 조건을 트리거합니다. 왜 이것이 실패 했습니까? 인턴이나 다른 것 때문입니까?
Paul

인터프리터 구현으로 인해 false가 반환되는 이유는 다음과 같습니다. stackoverflow.com/questions/132988/…
Paul


@ArchitJain 예, 그 링크는 그것을 잘 설명합니다. 당신이 그것들을 읽을 때, 당신이 사용할 수있는 숫자가 무엇인지 알게 될 것입니다. 난 그냥 여전히 당신은 다른 사람뿐만 아니라 않는 가정 그것에게 좋은 아이디어가되지 않습니다이 아는 것을 :) 할 수있는 좋은 생각이 아닌 이유가 설명 텐데 (또는 그 내면화 번호 범위 것이다 결코 변경)
마티아스 닐슨

20

파이썬에 대한 나의 제한된 경험에서 is두 객체를 비교하여 동일한 값을 가진 두 개의 다른 객체와 동일한 객체인지 확인하는 데 사용됩니다. ==값이 동일한 지 확인하는 데 사용됩니다.

다음은 좋은 예입니다.

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

s1유니 코드 문자열이며 s2일반 문자열입니다. 그것들은 같은 타입은 아니지만 같은 값입니다.


17

나는 'is'비교가 거짓으로 평가 될 때 두 개의 별개의 객체가 사용된다는 사실과 관련이 있다고 생각합니다. 그것이 true로 평가되면, 그것은 내부적으로 동일한 정확한 객체를 사용하고 새로운 객체를 생성하지 않음을 의미합니다. 아마도 2 초 정도의 시간 안에 객체를 만들었을 때와 최적화 된 객체 사이에 시간 간격이 크지 않기 때문입니다 동일한 객체를 사용합니다.

당신이 평등 연산자를 사용해야하는 이유입니다 ==,하지 is문자열 오브젝트의 값을 비교.

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

이 예제에서는 이전에 '1'과 다른 문자열 객체 인 s2를 만들었지 만 s인터프리터가 처음에 '1'에 할당하지 않은 것과 동일한 객체를 사용하지 않았기 때문에와 동일한 객체가 아닙니다. 내가 가지고 있다면 그것들을 같은 대상으로 만들었을 것입니다.


3
.replace()이 문맥에서 예제로 사용 하는 것은 의미가 혼동 될 수 있기 때문에 아마도 최선이 아닙니다. s2 = s2.replace()것입니다 항상 만드는 새로운 문자열 객체를,에 새 문자열 객체를 할당 s2하고 그 문자열 객체 처분 s2에 포인트로 사용했다. 그래서 당신이 그렇게하더라도 s = s.replace('one', 'one')여전히 새로운 문자열 객체를 얻을 것입니다.
Daniel Pryden

13

나는 이것이 "interned"문자열이라고 알려져 있습니다. 파이썬은 최적화 된 모드에서 컴파일 할 때 Java와 C 및 C ++도 마찬가지입니다.

두 개의 문자열 객체를 만들어 메모리를 낭비하는 대신 두 개의 동일한 문자열을 사용하는 경우 내용이 동일한 모든 내부 문자열은 동일한 메모리를 가리 킵니다.

같은 내용을 가진 두 문자열이 같은 문자열 객체를 가리 키기 때문에 Python "is"연산자는 True를 반환합니다. 이것은 Java와 C에서도 발생합니다.

이것은 메모리 절약에만 유용합니다. 다양한 인터프리터와 컴파일러 및 JIT 엔진이 항상 그렇게 할 수 없기 때문에 문자열 동등성을 테스트하는 데 의존 할 수 없습니다.


12

위의 답변이 언어 참조를 인용하지 않기 때문에 질문이 오래되었지만 질문에 대답하고 있습니다.

실제로 is 연산자는 동일성을 검사하고 == 연산자는 동등성을 검사합니다.

언어 참조에서 :

유형은 객체 동작의 거의 모든 측면에 영향을줍니다. 객체 아이덴티티의 중요성조차도 어떤 의미에서 영향을받습니다. 불변 타입의 경우, 새로운 값을 계산하는 연산은 실제로 동일한 타입과 값을 가진 기존 객체에 대한 참조를 반환 할 수 있지만, 가변 객체의 경우 이것은 허용되지 않습니다 . 예를 들어, a = 1 이후; b = 1, a 및 b는 구현에 따라, 그러나 c = [] 이후에 값이 1 인 동일한 객체를 참조하거나 참조하지 않을 수 있습니다. d = [], c 및 d는 새로 생성 된 서로 다른 두 개의 빈 목록을 참조합니다. c = d = []는 c와 d에 동일한 객체를 할당합니다.

따라서 위의 문장에서 "is"로 검사하면 불변 유형 인 문자열이 실패하고 "is"로 검사하면 성공할 수 있음을 알 수 있습니다

불변의 타입 인 int, tuple도 마찬가지입니다.


8

==오퍼레이터 테스트 값 등가. is운영자 테스트 오브젝트 ID는, 두 여부 파이썬 테스트는 정말 같은 객체 (메모리에 같은 주소 즉, 라이브)입니다.

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

이 예에서, 파이썬은 모두, 하나 개의 문자열 객체를 생성 a하고 b그것에 의미합니다. 그 이유는 파이썬이 내부적으로 일부 문자열을 최적화로 캐시하고 재사용하기 때문입니다. 실제로 a와 b가 공유하는 문자열 '바나나'가 메모리에 있습니다. 정상적인 동작을 트리거하려면 더 긴 문자열을 사용해야합니다.

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

두 개의 목록을 만들면 두 개의 객체가 생성됩니다.

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

이 경우 두 목록이 동일한 요소를 갖지만 동일한 객체가 아니기 때문에 동일하지 않기 때문에 두 목록이 동일하다고 말할 수 있습니다. 두 개체가 동일하면 개체도 동일하지만 동일하면 반드시 동일하지는 않습니다.

경우 a개체를 참조하고 할당 b = a, 다음 두 변수가 같은 객체를 참조 :

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

7

is메모리 위치를 비교합니다. 객체 수준 비교에 사용됩니다.

==프로그램의 변수를 비교합니다. 값 수준에서 확인하는 데 사용됩니다.

is 주소 수준의 동등성을 검사

== 가치 수준의 동등성을 확인


3

is신원 테스트, ==평등 테스트입니다 ( Python Documentation 참조 ).

대부분의 경우, 만약 a is b다음, a == b. 그러나 다음과 같은 예외가 있습니다.

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

따라서 is항등 테스트는 절대로하지 않고 신원 테스트 에만 사용할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.