티스토리 뷰

반응형

파이썬에서 동일한 것을 비교하는 구문은 두 가지가 있다. 등호가 두 개 붙어있는 연산자 '=='와 파이썬 만의 고유 문법인 'is'가 존재한다.

 

보통 둘은 구분을 하지 않고 사용한다. 그럼, 이 두 연산자는 아무런 차이가 없을까? 다음 코드를 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sample = []
sample.append("Same?")
 
if sample == ["Same?"]:
    print("Same!")
else:
    print("Different!")
 
if sample is ["Same?"]:
    print("Same!")
else:
    print("Different!")
    
# Same!
# Different!
cs

 

위의 '=='의 경우 참이 나왔지만, 'is'의 경우 거짓이 나온 것을 확인할 수 있다. 두 연산자에 어떤 차이가 있길래 이런 결과가 나오는 것일까? 이번 포스팅에서 알아보도록 하자.

thumbnail
두 연산자의 차이를 알아보자.


1. == 과 'is'

먼저, 다른 언어에서도 사용되는 비교 연산자 '=='부터 알아보자. '=='는 값(value)이 동일한지 확인하는 연산자이다.

 

다른 말로, 만약 동일한 주소값이 아니더라도, 같은 값을 지니고 있다면 True를 반환하고, 다른 값을 지니고 있다면 False를 반환한다.

 

이와 별개로, 'is'도 비교 연산자이긴 하다. 다만 'is'는 같은 객체(object)인지 확인하는 연산자이다.

 

다른 말로, 동일한 값을 가지면서 동일한 주소 값을 가져야 한다는 의미라 할 수 있다. 조금 더 어려운 말로, 

 

한 마디로 이렇게 설명할 수 있다.

a is b 는 a == b and id(a) == id(b) 이다.

id함수를 모르는 사람을 위하여 간략히 설명하면 id(x)는 x에 대한 고윳값을 출력하는 함수라 생각하면 된다. 즉, 같은 id를 가진 두 객체는 같은 객체이고, 메모리 상에서 같은 공간을 차지하고 있다고 생각해도 된다.

 

예시를 들어보자.

 

대부분의 경우 '=='와 'is'가 같은 결과를 낸다. 하지만, 다음과 같은 경우 list, dict형은 다른 결과를 출력한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# ------------------------
 
# integer
print(1 == 1)
# True
print(1 is 1)
# True
 
# ------------------------
 
# string
print("" == "")
# True
print("" is "")
# True
 
# ------------------------
 
# None
print(None == None)
# True
print(None is None)
# True
 
# ------------------------
# list
print([] == [])
# True
print([] is [])
# False
 
# ------------------------
 
# dict
print({} == {})
# True
print({} is {})
# False
 
# ------------------------
 
# tuple
print(() == ())
# True
print(() is ())
# True
 
# ------------------------
 
cs

 

이외 같은 경우 헷갈리는 결과를 낸다. 왜 어떤 것은 같은 결과를 내지만 어떤 것은 다른 결과를 내는 건가?

 

왜 그럴까? 파이썬(정확히 CPython, 내부가 C로 이루어진 파이썬)은 몇몇 객체에 대하여 싱글턴(singleton) 방식과 캐싱(caching) 방식을 차용하기 때문이다.


2. 더 구체적인 설명

조금 어려운 내용일 수 있지만, 이번 포스팅을 이해하기 위한 하나의 과정이라 생각하면 될 것 같다.

 

파이썬은 메모리를 효율적으로 관리하기 위하여 몇 가지 객체는 변수에 주소 값만 담는다.

 

예를 들면 True, False, None, 빈 tuple, 모듈, enum 등등은 다른 변수에 할당하여도 같은 주소 값을 가진다.

 

1
2
3
4
5
6
7
a, b = TrueTrue
print(id(a) == id(b))
# True, 같은 id를 가진다.
 
a, b = NoneNone
print(id(a) == id(b))
# True, 같은 id를 가진다.
cs

 

위의 경우 a, b라는 다른 변수에 True와 None을 담아도 같은 id값을 가지는 것을 확인할 수 있다.

 

혹은 정수형(int), 문자열(string), 튜플(tuple)과 같이 immutable, 즉 불변 값들은 캐싱과 싱글턴 객체를 활용하여 같은 주소 값들을 가지도록 파이썬 내부에서 자동으로 최적화한다.

 

이 경우 같은 id를 가지게 되어 'a is b'는 True를 가지게 되는 것이다.

 

list나 dictionary 자료형은 다르다. 이들은 mutable 하기도 하고 하나의 고유한 값을 가지는 것이 아니기에 파이썬에서 하나하나 다른 객체로 만든다. (애초에 동적으로 메모리를 할당해야 해서 굳이 같은 메모리에 묶어 놓을 필요가 없기도 하다.)

 

따라서, 같은 값은 가진다고 해도 id의 값은 다르게 되고 'a is b'는 False를 가지게 되는 것이다.

 

싱글턴 객체와 캐싱에 대한 자세한 설명은 생략하고, 별도의 포스팅 주제로 잡아야 할 만큼 깊은 주제를 가진 내용이다.


CPython이 아닌 Jython(Java 기반 파이썬), IronPython, PyPy에서는 다른 방식으로 작동할 수 있다. 이 경우 다른 결과가 나올 수 있지만, 같은 맥락으로 실험해보면 감을 잡을 수 있으리라 생각한다.

 

 

반응형
댓글
Total
Today
Yesterday
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함