본문 바로가기

Computer/Python

"is" vs "=="

반응형

[개발 잡학/Python] - 파이썬과 객체


파이썬에서 "is"와 "=="는 두 개의 객체가 같은지를 True/False로 반환하는 operator 입니다. 정확하게는 "is"는 identity operator, "=="는 equality operator 인데요, 이번 포스트에서는 이 두개의 operator의 차이를 알아보도록 하겠습니다.

"is"

"is"나 "is not"은 두 객체의 identity, 메모리 주소가 동일한지를 비교합니다. 즉, 두 객체가 메모리 상에서 같은 곳에 위치하느냐 판단하는 operator인 것이죠. id() 메소드를 이용하면 객체의 메모리 주소를 알 수 있고 (CPython) id() 같은 built-in 함수조차 메모리 상의 주소를 가지고 있음을 알 수 있습니다.

>>> help(id)
Help on built-in function id in module builtins:
id(obj, /)
    Return the identity of an object.
    
    This is guaranteed to be unique among simultaneously existing objects.
    (CPython uses the object's memory address.)

>>> id(id)
2730750577216

또한, 자주 쓰이는 -5부터 256까지의 정수와 아스키 문자는 메모리의 고정된 주소에 위치하므로 이 값을 가지는 여러 객체의 (변수) 메모리 주소는 같습니다. sys.intern 함수를 이용해서 문자열을 intern 시킬 수 있습니다. 다음과 같이 a, b는 본래 다른 메모리 주소를 가지는 다른 객체이지만 (id가 다르죠.) intern 시킴으로써 같은 메모리 주소를 가리키게 됩니다. 또한 None, True, False 등도 자동으로 intern 되어 있습니다. 하지만 일반적으로 같은 값을 가지는 서로 다른 객체는 메모리 상에서 서로 다른 공간에 위치합니다.

>>> from sys import intern
>>> a = 'hello world'
>>> b = 'hello world'
>>> a is b
False
>>> id(a)
1603648396784
>>> id(b)
1603648426160

>>> a = intern(a)
>>> b = intern(b)
>>> a is b
True
>>> id(a)
1603648396784
>>> id(b)
1603648396784

리스트같은 가변 객체에 대해 살펴보면 단순한 referencing은 id가 같지만 같은 값을 가지는 리스트를 별개로 선언하면 서로 다른 메모리 주소를 가지게 됩니다. 따라서 두번째 경우는 b 리스트를 바꾼다 하더라도 a 리스트에 반영되지 않겠죠.

>>> a = [1, 2, 3]
>>> b = a
>>> id(a)
2570926056520
>>> id(b)
2570926056520

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a is b
False
>>> id(a)
2356388925576
>>> id(b)
2356388952648

 

"=="

따라서 같은 값을 가지는 여러 객체는 메모리 상에 다른 공간에 위치할 수 있으므로 우리가 객체가 가지는 값 자체만 동일한지를 비교하려면 "=="이나 "!="를 사용하여야 합니다. 예를 들어 copy를 통해 같은 값을 지니는 다른 객체를 생성한다면, "is"는 False, "=="는 True가 되겠죠.

>>> a = [1, 2, 3]
>>> b = a.copy()
>>> a
[1, 2, 3]
>>> b
[1, 2, 3]

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

>>> id(a)
2570926058312
>>> id(b)
2570926057736

또한, 한 줄에서 비교를 하게 되면 왼쪽, 오른쪽 객체가 다른 메모리 주소에 위치하게 되므로 "is"는 False를 리턴합니다.

>>> [1,2,3] == [1,2,3]
True
>>> [1,2,3] is [1,2,3]
False

특히, "=="는 파이썬의 "__eq__" 메소드를 재정의 (operator overloading) 함으로써 수치나 문자열이 아닌 객체에 대해서도 equality 여부를 정의할 수 있습니다. 예를 들어 다른 객체와 길이가 같으면 True를 반환하는 equality를 정의할 수 있는 것이죠.

class SillyString(str):
    # This method gets called when using == on the object
    def __eq__(self, other):
        print(f'comparing {self} to {other}')
        # Return True if self and other have the same length
        return len(self) == len(other)

따라서 문자열 뿐만 아니라 길이가 같은 리스트와 비교했을 때에도 True/False를 반환하게 됩니다. "!=" operator에 대해서는 "__ne__" 메소드를 재정의하면 됩니다.

>>> # Compare two strings
>>> 'hello world' == 'world hello'
False

>>> # Compare a string with a SillyString
>>> 'hello world' == SillyString('world hello')
comparing world hello to hello world
True

>>> # Compare a SillyString with a list
>>> SillyString('hello world') == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
comparing hello world to [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
True
반응형

'Computer > Python' 카테고리의 다른 글

ModuleNotFoundError 와 ImportError  (0) 2021.08.26
Vectorization  (0) 2021.08.14
파이썬 실수 내림/올림  (0) 2021.08.03
Shallow copy vs Deep copy  (0) 2021.08.01
List Subtraction  (0) 2021.07.26