[python] “==”와“is”사이에 차이가 있습니까?

Google-fu 가 실패했습니다.

파이썬에서 동등성에 대해 다음 두 가지 테스트가 있습니까?

n = 5
# Test one.
if n == 5:
    print 'Yay!'

# Test two.
if n is 5:
    print 'Yay!'

인스턴스를 비교할 객체 ( list말)에 대해서도 마찬가지 입니까?

좋아요, 이런 종류의 질문에 대답합니다.

L = []
L.append(1)
if L == [1]:
    print 'Yay!'
# Holds true, but...

if L is [1]:
    print 'Yay!'
# Doesn't.

그렇다면 ==테스트 is가 동일한 객체인지 확인하기 위해 테스트하는 값은 어디 입니까?



답변

is변수가 참조하는 객체 True가 동일한 경우 두 변수가 동일한 객체를 가리키는 경우 반환 됩니다 ==.

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

# Make a new copy of list `a` via the slice operator, 
# and assign it to variable `b`
>>> b = a[:] 
>>> b is a
False
>>> b == a
True

귀하의 경우 두 번째 테스트는 Python이 구현 세부 사항 인 작은 정수 객체를 캐시하기 때문에 작동합니다. 더 큰 정수의 경우 작동하지 않습니다.

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True

문자열 리터럴에 대해서도 마찬가지입니다.

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

이 질문 도 참조하십시오 .


답변

==또는 사용시기를 알려주는 간단한 경험 법칙이 있습니다 is.

  • ==가치 평등을 위한 것 입니다. 두 객체의 값이 같은지 알고 싶을 때 사용하십시오.
  • is을위한 참조 평등 . 두 개의 참조가 동일한 객체를 참조하는지 알고 싶을 때 사용하십시오.

일반적으로 무언가를 간단한 유형과 비교할 때는 일반적으로 값이 같은지 확인 하므로을 사용해야합니다 ==. 예를 들어, 예제의 목적 은 문자 그대로 2와 동일한 객체를 참조 ==하는지 여부 x가 아니라 x의 값이 2 ( )인지 확인하는 것 입니다.


CPython 참조 구현의 작동 방식으로 인해 실수로 is정수의 참조 평등을 비교 하는 데 사용하면 예기치 않은 결과가 발생합니다 .

>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False

그것은 우리가 기대했던 것과 거의 같습니다. a그리고 b같은 가치를 가지지 만 별개의 실체입니다. 하지만 이건 어때?

>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True

이것은 이전 결과와 일치하지 않습니다. 무슨 일이야? 파이썬의 참조 구현은 성능상의 이유로 -5..256 범위의 정수 객체를 단일 인스턴스로 캐시합니다. 다음은이를 보여주는 예입니다.

>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
... 
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False

이것은 사용하지 않는 또 다른 명백한 이유 is입니다. 값 평등에 잘못 사용하면 동작이 구현에 맡겨집니다.


답변

==값이 같은지 확인하고 값이 is정확히 동일한 개체인지 확인합니다.


답변

파이썬 ==과 차이점이 is있습니까?

예, 그들은 매우 중요한 차이점이 있습니다.

==: 동등성 점검-의미론은 동일한 오브젝트가 아닐 수도있는 동등한 오브젝트가 동일한 것으로 테스트한다는 것입니다. 현상태대로 설명서를 말한다 :

연산자 <,>, ==,> =, <= 및! =는 두 개체의 값을 비교합니다.

is: 신원 확인-의미는 객체 (메모리에 보유 된) 객체라는 것입니다. 다시, 문서는 말합니다 :

연산자 isis not개체 식별을위한 테스트 : x is y경우에만, 사실 xy같은 객체입니다. 객체 식별은 id()기능을 사용하여 결정 됩니다. x is not y역 진리 값을 산출합니다.

따라서 ID 확인은 객체의 ID가 같은지 확인하는 것과 같습니다. 그건,

a is b

와 같다:

id(a) == id(b)

where id는 “함께 존재하는 객체들 사이에서 고유함을 보장하는”정수를 리턴하는 내장 함수이며 (참조 help(id)) 그리고 어디에 a그리고 b임의의 객체입니다.

다른 사용법

이러한 의미를 의미론에 사용해야합니다. 사용 is의 신원을 확인하고 ==평등을 확인 할 수 있습니다.

따라서 일반적으로 is신원 확인에 사용 합니다. 이것은 일반적으로 문서에서 “단일”이라고하는 메모리에 한 번만 존재해야하는 객체를 검사 할 때 유용합니다.

사용 사례는 is다음과 같습니다.

  • None
  • 열거 형 값 (enum 모듈에서 열거 형을 사용하는 경우)
  • 일반적으로 모듈
  • 일반적으로 클래스 정의에서 생성 된 클래스 객체
  • 일반적으로 함수 정의로 인한 함수 객체
  • 메모리에 한 번만 존재해야하는 다른 것 (일반적으로 모든 싱글 톤)
  • 신원으로 원하는 특정 객체

일반적인 사용 사례는 ==다음과 같습니다.

  • 정수를 포함한 숫자
  • 기울기
  • 세트
  • 사전
  • 커스텀 가변 객체
  • 대부분의 경우 다른 내장 불변 객체

일반적인 사용 사례, 다시, 대한 ==, 당신은하지 않을 수 있습니다 할 개체입니다 같은 대신이 될 수있다, 객체 상응

PEP 8 방향

표준 라이브러리를위한 공식 파이썬 스타일 가이드 인 PEP 8은 다음과 같은 두 가지 사용 사례를is 언급 합니다 .

싱글 톤과의 비교 None는 항상 등호 연산자를 사용하지 않고 is또는
로 수행해야합니다 is not.

또한 if x실제로 의미하는 if x is not None경우 (예 : 기본적으로 변수 또는 인수가 None
다른 값으로 설정되어 있는지 테스트 할 때 ) 기록에주의하십시오 . 다른 값에는 부울 컨텍스트에서 false 일 수있는 유형 (예 : 컨테이너)이있을 수 있습니다!

동일성에서 평등 추론

만약 is사실이라면, 평등은 일반적 으로 추론 될 수 있습니다 – 논리적으로, 만약 객체가 그 자체라면, 그것은 동등하게 테스트되어야합니다.

대부분의 경우이 논리는 사실이지만 __eq__특수한 방법 의 구현에 의존합니다 . 문서에서 말한 것처럼

동등 비교 ( ==!=) 의 기본 동작 은 객체의 ID를 기반으로합니다. 따라서 동일한 ID를 가진 인스턴스를 동등하게 비교하면 동일하게되고 다른 ID를 가진 인스턴스를 동등하게 비교하면 불평등이 발생합니다. 이 기본 동작의 동기는 모든 객체가 반사적이어야한다는 요구입니다 (즉, x는 y는 x == y를 의미합니다).

일관성을 위해 다음 사항을 권장합니다.

평등 비교는 반사적이어야합니다. 다시 말해, 동일한 객체는 동일하게 비교해야합니다.

x is y 암시 x == y

이것이 커스텀 객체의 기본 동작임을 알 수 있습니다.

>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)

반대되는 것도 일반적으로 사실입니다. 만약 무언가가 동일하지 않은 것으로 테스트된다면, 당신은 그것들이 같은 객체가 아니라고 추론 할 수 있습니다.

평등에 대한 테스트를 사용자 정의 할 수 있으므로이 유추가 모든 유형에 대해 항상 적용되는 것은 아닙니다.

예외

주목할만한 예외는 nan항상 자신과 같지 않은 것으로 테스트합니다.

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

동일성을 확인하는 것보다 신원을 확인하는 것이 훨씬 빠릅니다 (재귀 적으로 멤버를 확인해야 할 수도 있음).

그러나 둘 이상의 객체를 동등한 것으로 찾을 수있는 동일성을 대체 할 수는 없습니다.

목록과 튜플의 동등성을 비교하면 객체의 동일성이 동일하다고 가정합니다 (빠른 검사이기 때문에). 논리가 일치하지 않으면 다음과 같이 모순이 발생할 수 있습니다 nan.

>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True

주의 사항 :

문제는 is정수를 비교하는 데 사용하려고합니다 . 정수의 인스턴스가 다른 참조에서 얻은 인스턴스와 동일한 인스턴스라고 가정해서는 안됩니다. 이 이야기는 이유를 설명합니다.

주석 작성자는 작은 정수 (-5 ~ 256 포함)가 동등성을 검사하는 대신 파이썬에서 싱글 톤이라는 사실에 의존하는 코드를 가지고있었습니다.

와우, 이것은 교활한 버그로 이어질 수 있습니다. a와 b가 일반적으로 작은 숫자이기 때문에 a가 b인지 확인하는 코드가 있습니다. a와 b가 결국 캐시되지 않을 정도로 커졌기 때문에 버그는 현재 6 개월이 지난 후에야 발생했습니다. – gwg

그것은 개발에 일했다. 일부 단위 테스트를 통과했을 수 있습니다.

그리고 코드가 256보다 큰 정수를 검사하기 전까지는 프로덕션 환경에서 작동했습니다.이 시점에서 프로덕션에서 실패했습니다.

이는 코드 검토 또는 스타일 검사기에서 발생할 수있는 프로덕션 실패입니다.

강조하겠습니다 : 정수를 비교 하는 is데 사용하지 마십시오 .


답변

차이 무엇 is==?

==그리고 is다른 비교입니다! 다른 사람들이 이미 말했듯이 :

  • == 객체의 값을 비교합니다.
  • is 객체의 참조를 비교합니다.

파이썬 이름이 경우, 예를 들어, 개체 참조 value1하고 value2참조 int값을 저장하는 경우 1000:

value1 = 1000
value2 = value1

여기에 이미지 설명을 입력하십시오

때문에이 value2같은 객체를 참조 is하고 ==줄 것이다 True:

>>> value1 == value2
True
>>> value1 is value2
True

다음 예에서 이름 value1과는 value2다른 참조 int, 인스턴스도 모두 저장하는 경우는 같은 정수를 :

>>> value1 = 1000
>>> value2 = 1000

여기에 이미지 설명을 입력하십시오

저장되어있는 같은 값 (정수) 때문에 ==True, 그것은 종종 “값 비교”이라고 이유의 그. 그러나 이들은 다른 객체이기 때문에 is반환 False됩니다.

>>> value1 == value2
True
>>> value1 is value2
False

언제 사용합니까?

일반적으로 is훨씬 빠른 비교입니다. 그렇기 때문에 CPython 은 작은 정수, 일부 문자열 등과 같은 특정 객체를 캐시 (또는 재사용 이 더 나은 용어 일 수 있음)하는 이유입니다 . 그러나 이것은 가능하지 않은 경우에도 경고없이 변경 될 수있는 구현 세부 사항 으로 취급해야합니다 .

당신은해야 에만 사용is 하면 경우 :

  • 두 객체가 실제로 동일한 객체인지 확인하고 싶습니다 (동일한 “값”이 아님). 단일 객체를 상수로 사용하는 경우 예로들 수 있습니다 .
  • 값을 파이썬 상수 와 비교하고 싶습니다 . 파이썬의 상수는 다음과 같습니다

    • None
    • True1
    • False1
    • NotImplemented
    • Ellipsis
    • __debug__
    • 클래스 (예 : int is int또는 int is float)
    • 내장 모듈 또는 타사 모듈에 추가 상수가있을 수 있습니다. 예를 들어 np.ma.maskedNumPy 모듈에서)

에서 다른 모든 경우에 당신은 사용해야== 평등을 확인 할 수 있습니다.

동작을 사용자 정의 할 수 있습니까?

==다른 답변에서 아직 언급되지 않은 측면이 있습니다 . Pythons “Data model” 의 일부입니다 . 즉, __eq__방법을 사용하여 동작을 사용자 정의 할 수 있습니다 . 예를 들면 다음과 같습니다.

class MyClass(object):
    def __init__(self, val):
        self._value = val

    def __eq__(self, other):
        print('__eq__ method called')
        try:
            return self._value == other._value
        except AttributeError:
            raise TypeError('Cannot compare {0} to objects of type {1}'
                            .format(type(self), type(other)))

이 메소드가 실제로 호출되었다는 것을 보여주는 인공적인 예일뿐입니다.

>>> MyClass(10) == MyClass(10)
__eq__ method called
True

기본적으로 ( __eq__클래스 나 수퍼 클래스에서 다른 구현을 찾을 수 없는 경우 ) 다음을 __eq__사용합니다 is.

class AClass(object):
    def __init__(self, value):
        self._value = value

>>> a = AClass(10)
>>> b = AClass(10)
>>> a == b
False
>>> a == a

따라서 __eq__사용자 정의 클래스에 대한 참조 비교보다 “더 많은 것”을 원하면 실제로 구현 하는 것이 중요합니다 !

반면에 is수표를 사용자 정의 할 수 없습니다 . 항상 비교합니다 단지 동일한 기준이있는 경우.

이러한 비교가 항상 부울을 반환합니까?

때문에 __eq__재 구현 또는 오버라이드 (override) 할 수 있습니다, 그것은 반환에 국한되지 것 TrueFalse. 그것은 무엇이든 반환 할 수 있습니다 (그러나 대부분의 경우 부울을 반환해야합니다!).

예를 들어 NumPy 배열의 ==경우 배열을 반환합니다.

>>> import numpy as np
>>> np.arange(10) == 2
array([False, False,  True, False, False, False, False, False, False, False], dtype=bool)

그러나 is수표는 항상 True또는 False!


1 Aaron Hall이 언급 한대로 :

일반적으로 당신은하지 말아야 is True또는 is False하나 일반적으로 암시 적으로 변환하는 상황에서 이러한 “확인”을 사용하기 때문에 검사 조건을 (AN의 예를 들어 부울에 if문). 따라서 is True비교 암시 적 부울 캐스트는 단순히 부울 캐스트를 수행하는 것보다 더 많은 작업을 수행하며 부울로 제한됩니다 (pythonic으로 간주되지 않음).

PEP8 언급처럼 :

부울 값을 비교하지 마십시오 True또는 False사용 ==.

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:

답변

그들은 완전히 다릅니다 . 동등성 is==검사 하는 동안 (두 피연산자의 유형에 따라 달라지는 개념) 오브젝트를 확인합니다.

is“가 작은 정수 (예 : 5 == 4 + 1)에서 올바르게 작동하는 것 같습니다. CPython싱글 톤으로 만들어서 범위 (-5-256)의 정수 저장을 최적화 하기 때문 입니다. 이 동작은 전적으로 구현에 따라 다르며 모든 방식의 작은 변환 작업에서 유지되는 것은 아닙니다.

예를 들어 Python 3.5는 짧은 문자열을 싱글 톤으로 만들지 만 슬라이싱하면이 동작이 중단됩니다.

>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False


답변

https://docs.python.org/library/stdtypes.html#comparisons

is동일성
==검정 테스트

각 (작은) 정수 값은 단일 값에 매핑되므로 모든 3은 동일하고 동일합니다. 이것은 언어 사양의 일부가 아닌 구현 세부 사항입니다.