Python의 "is"연산자 이해


110

is연산자는 변수의 값하지만, 인스턴스 자신을 일치하지 않습니다.

그것은 정말로 무엇을 의미합니까?

두 변수에 이름 xy지정하고 두 변수 에 동일한 값을 할당하는 두 개의 변수를 선언 했지만 is연산자를 사용하면 false를 반환합니다 .

설명이 필요합니다. 다음은 내 코드입니다.

x = [1, 2, 3]
y = [1, 2, 3]

print(x is y)  # It prints false!

답변:


181

is운영자가 테스트 하는 것을 오해했습니다 . 두 변수가 동일한 값을 갖는 것이 아니라 두 변수가 동일한 객체를 가리키는 지 테스트 합니다.

is운영자를 위한 문서에서 :

개체 ID에 대한 연산자 isis not테스트 : 과 동일한 개체 인 x is y경우에만 true 입니다.xy

==대신 연산자를 사용하십시오 .

print(x == y)

이것은 인쇄합니다 True. x그리고 y두 가지 별도의 목록 :

x[0] = 4
print(y)  # prints [1, 2, 3]
print(x == y)   # prints False

당신이 사용하는 경우 id()기능을 해당를 볼 수 있습니다 xy다른 식별자가 :

>>> id(x)
4401064560
>>> id(y)
4401098192

그러나 할당 y하면 x두 가지 모두 동일한 객체를 가리 킵니다.

>>> x = y
>>> id(x)
4401064560
>>> id(y)
4401064560
>>> x is y
True

is쇼 모두 동일한 개체가,이 반환됩니다 True.

Python에서 이름은 값을 참조하는 레이블 일뿐입니다 . 동일한 객체를 가리키는 여러 이름을 가질 수 있습니다. is두 개의 이름이 하나의 동일한 객체를 가리키는 지 알려줍니다. ==두 이름이 같은 값을 가진 객체를 참조하는지 알려줍니다.


13
그래서 A is Bid(A) == id(B).
imallett

2
@imallett : id(A)변수에 저장하지 않고 나중에 variable == id(B)계속 작동 할 것으로 예상하는 경우 동일한 테스트에 대한 프록시입니다 . 경우 A그 사이에 삭제 한 후 B동일한 메모리 위치를 주어졌다 수 있습니다.
Martijn Pieters

1
댓글 형식을 지정할 수 없습니다. 그러나 흥미로운 것이 있습니다. >>> : X = 5 \n>>> Y = 5 \n>>> X는 Y이다 \n트루 \n>>> X == Y \n트루 \n>>>\n
Haranadh

5
작은 정수는 자주 사용되기 때문에 CPython에서 인턴됩니다. 최적화입니다. x = 5; y = 5; x는 y => true이므로 id (x) == id (y)입니다. 재사용되는 동일한 정수 객체입니다. 정수는 변경할 수 없기 때문에 Python에서 작동합니다. x = 1.0; y = 1.0 또는 x = 9999; y = 9999, float 및 더 큰 정수는 인턴되지 않기 때문에 동일한 ID가 아닙니다.
Magnus Lyckå

1
@ MagnusLyckå 불변 개체를 캐시 할 수있는 다른 최적화가 있습니다. 예를 들어, 새로운 함수에서 또는 인터랙티브 인터프리터에서 분리 세미콜론과 함께 예제를 실행하면 동일한 ID를 가지고 있음을 알 수 있습니다.
Martijn Pieters

60

또 다른 중복 은 두 개의 동일한 문자열이 일반적으로 동일하지 않은 이유를 묻는 것이 었는데, 여기에서는 실제로 대답하지 않았습니다.

>>> x = 'a' 
>>> x += 'bc'
>>> y = 'abc'
>>> x == y
True
>>> x is y
False

그렇다면 왜 그들은 같은 문자열이 아닌가? 특히 다음과 같은 경우 :

>>> z = 'abc'
>>> w = 'abc'
>>> z is w
True

두 번째 부분은 잠시 미루겠습니다. 첫 번째가 어떻게 사실 일 수 있습니까?

인터프리터는 문자열 값을 문자열 객체에 매핑하는 테이블 인 "인터 닝 테이블"을 가져야하므로 내용이있는 새 문자열을 만들 때마다 'abc'동일한 객체를 반환합니다. Wikipedia 에는 인턴이 어떻게 작동하는지에 대한 자세한 논의가 있습니다.

그리고 파이썬 에는 문자열 인터 닝 테이블이 있습니다. sys.intern메서드를 사용하여 수동으로 문자열을 인턴 할 수 있습니다 .

사실, 파이썬입니다 허용 자동으로 인턴 어떤 불변의 유형 있지만 필요 그렇게. 다른 구현은 다른 값을 인턴합니다.

CPython (사용중인 구현을 모르는 경우 사용하는 구현)은 작은 정수와 같은 일부 특수 싱글 톤을 자동 인턴 False하지만 문자열 (또는 큰 정수, 작은 튜플 또는 기타)은 제외합니다. 이것은 매우 쉽게 볼 수 있습니다.

>>> a = 0
>>> a += 1
>>> b = 1
>>> a is b
True
>>> a = False
>>> a = not a
>>> b = True
a is b
True
>>> a = 1000
>>> a += 1
>>> b = 1001
>>> a is b
False

OK, 그러나 왜했다 zw동일?

그것은 인터프리터가 자동으로 인턴하는 것이 아니라 컴파일러 폴딩 값입니다.

동일한 컴파일 시간 문자열이 동일한 모듈에 두 번 나타나는 경우 (정확히 정의하기 어렵다는 의미입니다 r'abc'. 'abc',, 'a' 'b' 'c'은 (는) 모두 다른 리터럴이지만 동일한 문자열 이기 때문에 문자열 리터럴 과 동일하지 않지만 이해하기 쉽습니다.) 직관적으로) 컴파일러는 두 개의 참조가있는 문자열의 인스턴스를 하나만 만듭니다.

사실 컴파일러는 훨씬 더 나아갈 'ab' + 'c'수 있습니다 'abc'. 최적화 프로그램 에 의해 변환 될 수 있습니다 .이 경우 'abc'동일한 모듈에서 상수 와 함께 접힐 수 있습니다 .

다시 말하지만 이것은 Python이 허용되지만 반드시 수행해야하는 것은 아닙니다. 그러나이 경우 CPython은 항상 작은 문자열 (예 : 작은 튜플)을 접습니다. (대화 형 인터프리터의 문별 컴파일러는 한 번에 모듈 단위 컴파일러와 동일한 최적화를 실행하지 않으므로 대화 형으로 정확히 동일한 결과를 볼 수 없습니다.)


그렇다면 프로그래머로서 이것에 대해 어떻게해야합니까?

글쎄… ​​아무것도. 두 개의 불변 값이 동일한 지 신경을 쓸 이유가 거의 없습니다. a is b대신 사용할 수있는시기를 알고 싶다면 a == b잘못된 질문을하는 것입니다. a == b두 가지 경우를 제외하고 항상 사용하십시오 .

  • 같은 싱글 톤 값에 대한 더 읽기 쉬운 비교를 위해 x is None.
  • 변경 가능한 값의 경우 변경 xy.

1
훌륭한 설명, 특히 마지막에 귀하의 조언.
DavidG

자세한 설명에 감사드립니다. 누군가 알고합니까 : 경우에 wz있기 때문에 값을 접는 컴파일러의 동일, 왜 REPL에서이 또한 작업은, 심지어 사용 않는 id()참조를 확인하기 위해? Python 3.7에서 REPL 사용
Chi-chi

8

is실제로 동일한 객체 인 경우에만 true를 반환합니다. 동일하다면 하나의 변경 사항이 다른 하나에도 나타납니다. 다음은 차이점의 예입니다.

>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> print x is y
False
>>> z = y
>>> print y is z
True
>>> print x is z
False
>>> y[0] = 5
>>> print z
[5, 2, 3]

8

a로 프롬프트 중복 된 질문 이 비유 작동 할 수 있습니다 :

# - Darling, I want some pudding!
# - There is some in the fridge.

pudding_to_eat = fridge_pudding
pudding_to_eat is fridge_pudding
# => True

# - Honey, what's with all the dirty dishes?
# - I wanted to eat pudding so I made some. Sorry about the mess, Darling.
# - But there was already some in the fridge.

pudding_to_eat = make_pudding(ingredients)
pudding_to_eat is fridge_pudding
# => False

3
개인적인 취향 일 수도 있지만 (말장난이 아닌)이 비유가 도움이되는 것보다 더 혼란 스러웠고 냉장고에 푸딩이 없을 때 푸딩을 먹고 싶게 만들었습니다. (마크 랜섬의 대답은 더 지루하지만 더
Tom Close

1
@TomClose :이 질문에 대한 정답이 많기 때문에 경쾌함을위한 공간이 충분합니다. 또한 푸딩도 먹고 싶어요.
Amadan

5

is그리고 is not파이썬의 두 ID 연산자입니다. is연산자는 변수의 값을 비교하지 않고 변수의 ID를 비교합니다. 이걸 고려하세요:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> hex(id(a))
'0x1079b1440'
>>> hex(id(b))
'0x107960878'
>>> a is b
False
>>> a == b
True
>>>

위의 예는 ID (Cpython의 메모리 주소 일 수도 있음)가 ab(값이 동일하더라도) 둘 다에 대해 다르다는 것을 보여줍니다 . 그렇기 a is b때문에 두 피연산자의 ID가 일치하지 않아 false를 반환 한다고 말할 때 입니다. 그러나라고 말하면 연산은 두 피연산자에 동일한 값이 할당되어 있는지 확인 a == b하기 때문에 true를 반환 ==합니다.

흥미로운 예 (추가 등급) :

>>> del a
>>> del b
>>> a = 132
>>> b = 132
>>> hex(id(a))
'0x7faa2b609738'
>>> hex(id(b))
'0x7faa2b609738'
>>> a is b
True
>>> a == b
True
>>>

위의 예에서, 비록 ab두 개의 서로 다른 변수이다 a is b리턴이 True. 이 유형 때문이다 aIS int불변 오브젝트이다. 그래서 파이썬 (메모리를 절약하려고 생각합니다) b은 동일한 값으로 생성되었을 때 동일한 객체를 할당했습니다 . 이 경우 그래서, 일치와 변수의 신원 a is b밝혀졌다가되게합니다 True.

이것은 모든 불변 객체에 적용됩니다 :

>>> del a
>>> del b
>>> a = "asd"
>>> b = "asd"
>>> hex(id(a))
'0x1079b05a8'
>>> hex(id(b))
'0x1079b05a8'
>>> a is b
True
>>> a == b
True
>>>

도움이 되었기를 바랍니다.


이것은 정말 좋은 예입니다. 자세한 정보를 주셔서 감사합니다.
Haranadh

하지만 a = 123456789 b = 123456789
user2183078

파이썬 -5보다 작 거나 높은 모든 것은 256거짓입니다. Python은 [-5, 256] 범위의 숫자를 캐시합니다.
스마트 한

보여 주듯이 모든 불변 객체가 공유되는 것은 아닙니다. 이것은 파이썬 런타임이 일부 객체에 적용하지만 다른 객체에는 적용하지 않는 최적화입니다. 작은 정수를 공유하는 프로세스는 잘 문서화되어 있지만 문자열 인턴을 위한 것이라고 생각하지 않습니다 .
Mark Ransom

4

x is yid(x) == id(y)객체의 정체성을 비교하는 것과 같습니다 .

@ tomasz-kurgan이 아래 주석에서 지적했듯이 is연산자는 특정 개체에서 비정상적으로 작동합니다.

>>> class A(object):
...   def foo(self):
...     pass
... 
>>> a = A()
>>> a.foo is a.foo
False
>>> id(a.foo) == id(a.foo)
True

Ref;
https://docs.python.org/2/reference/expressions.html#is-not
https://docs.python.org/2/reference/expressions.html#id24


아닙니다. 대부분의 경우 유사하게 동작 할 수 있지만 항상 사실은 아닙니다. 참조 - 페이지의 맨 아래를, 총알 6 :> (...) (가)의, 특정 용도에 보이는 특이한 문제가 나타날 수 있습니다 운영자가 인스턴스 메소드, 또는 상수 그리고 최소한의 작업 예와 그와 관련된 비교처럼, :`class A (object) : def foo (self) : pass a = A () print a.foo is a.foo print id (a.foo) == id (a.foo)`
Tomasz Kurgan

3

여기에서 작은 정수로 확인할 수 있습니다. 257 이상의 숫자는 작은 정수가 아니므로 다른 객체로 계산됩니다.

==이 경우 대신 사용 하는 것이 좋습니다 .

자세한 정보는 여기 : http://docs.python.org/2/c-api/int.html


2

X는 배열을 가리키고 Y는 다른 배열을 가리 킵니다. 이러한 배열은 동일하지만 is연산자는 동일하지 않은 포인터를 살펴 봅니다.


5
파이썬에는 포인터가 없습니다. 용어를 강화해야합니다.
David Heffernan 2012

3
Java 및 기타 여러 언어와 마찬가지로 내부적으로 수행됩니다. 실제로 is운영자의 기능이이를 보여줍니다.
Neko 2011

5
구현 세부 사항은 중요하지 않습니다. 설명서에서는 "객체 ID"라는 용어를 사용합니다. 당신도 그래야합니다. "연산자는 객체 신원을 테스트하지 않습니다. x는 y는 x와 y가 동일한 객체 인 경우에만 참입니다. x는 y가 아닌 경우 역 진실 값을 산출합니다."
David Heffernan 2012

1
@Neko : CPython은 내부적으로 포인터를 사용합니다. 그러나 분명히 Jython (자바로 구현)과 PyPy (Python의 하위 집합에서 구현)는 포인터를 사용하지 않습니다. PyPy에서 일부 객체는 id요청하지 않는 한조차 갖지 않습니다 .
abarnert

1

개체 ID, 즉 변수가 메모리에서 동일한 개체를 참조하는지 여부를 비교합니다. 그것은처럼 ==Java 또는 C (포인터를 비교할 때)이다.


1

과일을 사용한 간단한 예

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist is newfruitlist )
print ( fruitlist is verynewfruitlist )
print ( newfruitlist is verynewfruitlist )

산출:

True
False
False

시도하면

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist == newfruitlist )
print ( fruitlist == verynewfruitlist )
print ( newfruitlist == verynewfruitlist )

출력이 다릅니다.

True
True
True

== 연산자는 변수의 내용 만 비교하기 때문입니다. 두 변수의 ID를 비교하려면 is 연산자를 사용하십시오.

식별 번호를 인쇄하려면 :

print ( id( variable ) )

-3

is운영자는 아무것도하지만의 영어 버전입니다 ==. 두 목록의 ID가 다르기 때문에 대답은 거짓입니다. 당신은 시도 할 수 있습니다:

a=[1,2,3]
b=a
print(b is a )#True

* 두 목록의 ID가 동일하기 때문에


is'의 영어 버전이 아닌 =='
데이비드 벅
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.