파이썬! = 작업 대“아님”


250

이 질문 에 대한 의견에서 사용을 권장하는 진술을 보았습니다.

result is not None

vs

result != None

차이점이 무엇인지 궁금해하는 이유가 무엇인지, 왜 다른 것이 더 좋은지 궁금합니다.



1
흠. 두 질문에 대한 대답은 모두 같은 개념이지만 여기서의 공감대와 자세한 답변은 동일성 및 평등 테스트 개념에 독립적으로 기여한다고 생각합니다.
viksit

답변:


301

==입니다 평등 테스트 . 오른쪽과 왼쪽이 동일한 물체인지 여부를 확인합니다 ( __eq__또는 __cmp__방법 에 따라 ).

is입니다 확인 시험은 . 오른쪽과 왼쪽이 동일한 객체인지 확인합니다. 메소드 호출이 수행되지 않으며 객체는 is작업에 영향을 줄 수 없습니다 .

척하려는 객체에 대해 신경 쓰지 않거나 와 비교할 때 객체가 깨지는 것을 방지하려는 경우와 같이 싱글 톤에 is(및 is not)를 사용 None합니다 .NoneNone


3
답변 주셔서 감사합니다-객체가 파손 될 수있는 상황에 대해 자세히 설명해 주시겠습니까?
viksit

3
@viksit. None메소드가 거의없고 속성이 거의 없습니다. __eq__테스트에서 메소드 또는 속성을 예상 한 경우 중단 될 수 있습니다. def __eq__( self, other ): return self.size == other.size. 예를 들어이면 other발생합니다 None.
S.Lott

36
이것을 이해하는 가장 좋아하는 방법은 다음 is과 같습니다 . Python 은 Java와 같습니다 ==. 파이썬 ==은 자바와 같습니다 .equals(). 물론 이것은 Java를 아는 경우에만 도움이됩니다.
MatrixFrog

4
@MatrixFrog :에서 PHP 나 자바 스크립트는 우리가 말하는 것 is처럼 ===(매우 같음), 반대로 is not같다 !==(정확하게 동일하지 않음).
Orwellophile

3
is not단일 연산자 입니까 , 아니면 is내부적으로 결과를 부정 not foo is bar합니까?
Asad Moosvi

150

먼저 몇 가지 용어를 살펴 보겠습니다. 질문에 대한 답변을 원하면 "질문 답변"으로 스크롤하십시오.

정의

객체 식별 : 객체를 생성 할 때 변수에 할당 할 수 있습니다. 그런 다음 다른 변수에 할당 할 수도 있습니다. 그리고 또 다른.

>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True

이 경우 cancel, closedismiss모든 메모리에 동일한 객체를 참조. 하나의 Button오브젝트 만 작성 했으며 세 개의 변수 모두이 하나의 오브젝트를 참조합니다. 우리는 그런 말을 cancel, close그리고 dismiss모두를 참조 동일 객체; 즉, 그들은 하나의 단일 객체를 참조합니다.

객체 평등 : 두 객체를 비교할 때 일반적으로 메모리에서 정확히 동일한 객체를 참조하는 것은 중요하지 않습니다 . 객체 평등을 사용하면 두 객체를 비교하는 방법에 대한 고유 한 규칙을 정의 할 수 있습니다. 당신이 쓸 때 if a == b:, 당신은 본질적으로 말하는 것 if a.__eq__(b):입니다. 이를 통해 __eq__메소드 를 정의 a하여 자신 만의 비교 논리를 사용할 수 있습니다.

평등 비교의 이론적 근거

근거 : 두 개체의 데이터는 동일하지만 동일하지 않습니다. (메모리에서 동일한 객체가 아닙니다.) 예 : 문자열

>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True

참고 : 파이썬은 메모리에 새로운 문자열을 만들지 않고 일반 문자열을 재사용 할만 큼 똑똑하기 때문에 여기에서 유니 코드 문자열을 사용합니다.

자, 내가이 유니 코드 문자열을 가지고 ab. 그들은 동일한 내용을 가지고 있지만 메모리에서 동일한 객체가 아닙니다. 그러나 우리가 그것들을 비교할 때, 그들이 동등하게 비교되기를 원합니다. 여기서 일어나는 일은 유니 코드 객체가 __eq__메소드 를 구현했다는 것입니다.

class unicode(object):
    # ...

    def __eq__(self, other):
        if len(self) != len(other):
            return False

        for i, j in zip(self, other):
            if i != j:
                return False

        return True

참고 : __eq__on unicode은 이것보다 확실히 효율적으로 구현됩니다.

이론적 근거 : 두 개체의 데이터는 다르지만 일부 키 데이터가 동일한 경우 동일한 개체로 간주됩니다. 예 : 대부분의 모델 데이터 유형

>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True

자, 내가이 개 델 모니터를 가지고 ab. 그들은 같은 제조사와 모델을 가지고 있습니다. 그러나 메모리에 동일한 데이터가 없거나 동일한 오브젝트가 없습니다. 그러나 우리가 그것들을 비교할 때, 그들이 동등하게 비교되기를 원합니다. 여기서 일어나는 일은 Monitor 객체가 __eq__메소드를 구현했다는 것입니다.

class Monitor(object):
    # ...

    def __eq__(self, other):
        return self.make == other.make and self.model == other.model

질문에 답변

와 비교할 때는 항상를 None사용하십시오 is not. 파이썬에는 싱글 톤이 없습니다. 메모리에는 인스턴스가 하나뿐입니다.

아이덴티티 를 비교하면 매우 빠르게 수행 할 수 있습니다. 파이썬은 당신이 말하는 객체가 전역 None 객체와 동일한 메모리 주소를 가지고 있는지 확인합니다-두 숫자를 매우 빠르게 비교합니다.

평등 을 비교함으로써 파이썬은 객체에 __eq__메소드 가 있는지 찾아야합니다 . 그렇지 않은 경우, __eq__메소드를 찾는 각 수퍼 클래스를 검사합니다 . 하나를 찾으면 파이썬은 그것을 호출합니다. 이 __eq__방법은 속도가 느리고 다른 객체가 인 경우 즉시 반환하지 않는 경우 특히 나쁩니다 None.

구현하지 않았습니까 __eq__? 그러면 파이썬은 아마도 __eq__메소드를 찾아서 object대신 사용할 것입니다-어쨌든 객체 신원을 확인합니다.

파이썬에서 대부분의 다른 것들을 비교할 때는을 사용 !=합니다.


42

다음을 고려하세요:

class Bad(object):
    def __eq__(self, other):
        return True

c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)

1
이것은 매우 유용하고 간단한 예입니다. 감사합니다.
msarafzadeh

18

None은 싱글 톤이므로 항등 비교는 항상 작동하는 반면 객체는를 통해 등가 비교를 가짜로 만들 수 있습니다 .__eq__().


아 흥미로운! 어떤 상황에서 평등 비교 btw를 위조하고 싶습니까? 나는 이것이 어떤 식 으로든 보안에 영향을 미친다고 생각합니다.
viksit 2019

1
평등을 위조하는 것이 아니라 평등을 이행 하는 것에 관한 입니다. 객체와 다른 객체를 비교하는 방법을 정의해야하는 많은 이유가 있습니다.
Thomas Wouters

1
보안 문제보다 더 혼란스러운 의미 라고 말하고 싶습니다 .
Greg Hewgill

2
나는 평등을 위조하는 이유에 대해 None언급하지 않았지만 None다른 유형에 대해 평등을 구현하는 데 따른 부작용으로 잘못된 행동 이 발생할 수 있습니다. 정확성에 영향을주기 때문에 보안에 큰 영향을 미치지는 않습니다.
Ignacio Vazquez-Abrams

아, 그래요 설명을위한 Thx.
viksit

10
>>> ()는 ()
진실
>>> 1은 1입니다
진실
>>> (1,) == (1,)
진실
>>> (1,)은 (1,)
그릇된
>>> a = (1,)
>>> b = a
>>> a는 b입니다
진실

일부 객체는 싱글 톤이므로 이것 is과 동일합니다 ==. 대부분은 아닙니다.


4
이들 중 대부분은 우연의 일치 / 구현 세부 사항으로 만 작동합니다. ()그리고 1본질적으로 싱글 없습니다.
Mike Graham

1
CPython 구현에서 작은 정수 ( -NSMALLNEGINTS <= n <= NSMALLPOSINTS) 및 빈 튜플 싱글 톤입니다. 실제로 문서화되거나 보장되지는 않지만 변경되지는 않습니다.
ephemient

3
그것이 구현되는 방식이지만 의미가 있거나 유용하거나 교육적이지 않습니다.
Mike Graham

1
특히 CPython이 유일한 Python 구현은 아닙니다. 파이썬 구현에 따라 다를 수있는 행동에 의존하는 것은 일반적으로 나에게 나쁜 생각 인 것 같습니다.
me_and
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.