비교

비교 에서 Python

7개의 연습 문제

비교 소개

파이썬의 비교 연산자(_파이썬 관계 연산자_라고도 해요)는 두 피연산자의 _값_을 살펴보고, comparison 조건이 충족되는지 여부에 따라 불리언 True 또는 False를 반환해요.

아래 표는 가장 흔히 쓰이는 파이썬 비교 연산자를 보여줘요.

연산자 연산 설명
> "보다 큼" a가 b보다 값이 엄격하게 크면 a > b는 True예요
< "보다 작음" a가 b보다 값이 엄격하게 작으면 a < b는 True예요
== "같음" a가 b와 값이 엄격하게 같으면 a == b는 True예요
>= "크거나 같음" a > b 또는 a == b이면 a >= b는 True예요
<= "작거나 같음" a < b 또는 a == b이면 a <= b는 True예요
!= "같지 않음" a == b가 False이면 a != b는 True예요
is "동일성" a와 b가 같은 _객체_일 때 오직 그때만 a is b는 True예요
is not "동일성 부정" a와 b가 같은 _객체_가 아닐 때 오직 그때만 a is not b는 True예요
in "포함 여부 검사" a가 b의 멤버, 부분집합 또는 원소이면 a in b는 True예요
not in "포함 여부 부정 검사" a가 b의 멤버, 부분집합 또는 원소가 아니면 a not in b는 True예요

이들은 모두 우선순위가 같아요(불리언 연산보다는 높고, 산술 연산이나 비트 연산보다는 낮아요).

서로 다른 데이터 타입 간의 비교

타입이 다른 객체는(숫자 타입을 제외하면) 기본적으로 결코 서로 같다고 비교되지 않아요. class의 서로 동일하지 않은 인스턴스 역시, 그 class가 기본 object 비교 동작을 바꾸는 특별한 리치 비교 메서드를 정의하지 않는 한, 서로 같다고 비교되지 않아요. (훨씬) 자세한 내용은 파이썬 문서의 값 비교를 참고해요.

숫자 타입은 (대부분) 이 타입 일치 규칙의 예외예요. 비교를 위해 타입이 암시적으로 변환될 수 있다면, integer는 float와 같다고 간주될 수 있어요(또는 octal이 hexadecimal와 같을 수 있어요).

그 밖의 숫자 타입(복소수, 십진수, 유리수)의 경우, 비교 연산자는 "말이 되는" 곳(암시적 변환이 결과를 바꾸지 않는 곳)에서 정의되지만, 기반 객체를 비교를 위해 정확히 변환할 수 없으면 TypeError를 던져요. 파이썬이 숫자 변환에 사용하는 규칙에 대한 자세한 내용은 파이썬 문서의 산술 변환을 참고해요.

>>> import fractions

# A string cannot be converted to an int.
>>> 17 == '17'
False

# An int can be converted to float for comparison.
>>> 17 == 17.0
True

# The fraction 6/3 can be converted to the int 2
# The int 2 can be converted to 0b10 in binary.
>>> 6/3 == 0b10
True

# An int can be converted to a complex 
# number with a 0 imaginary part.
>>> 17 == complex(17)
True

# The fraction 2/5 can be converted to the float 0.4
>>> 0.4 == 2/5
True

>>> complex(2/5, 1/2) == complex(0.4, 0.5)
True

숫자를 NaN(숫자가 아님) 타입과 순서대로 비교하면 결과는 항상 False예요. 파이썬의 NaN 정의에서 비롯된 혼란스러운 부작용은 NaN이 NaN과 결코 같다고 비교되지 않는다는 점이에요. 파이썬에서 NaN이 이렇게 정의된 이유가 궁금하다면, 국제 표준 제정과 관련된 이 NaN에 관한 Stack Overflow 게시물이 흥미로운 읽을거리가 될 거예요.

>>> x = float('NaN')

>>> 3 < x
False

>>> x < 3
False

# NaN never compares equal to NaN
>>> x == x
False

문자열 비교

문자열(str)은 각각의 유니코드 코드 포인트를 사용해 사전순으로 비교해요(각 코드 포인트를 내장 함수 ord()에 넘긴 결과이며, 이 함수는 int를 반환해요). 두 문자열의 모든 코드 포인트가 일치하고 순서도 같다면, 두 문자열은 같은 것으로 간주돼요. 이 비교는 '쌍별' 방식으로, 즉 첫 번째끼리, 두 번째끼리 하는 식으로 이루어져요. 파이썬 3.x에서는 str과 bytes를 직접 강제 변환하거나 비교할 수 없어요.

>>> 'Python' > 'Rust'
False

>>> 'Python' > 'JavaScript'
True

# Examples with Mandarin.
# hello < goodbye
>>> '你好' < '再见'
True

# ord() of first characters
>>> ord('你'), ord('再')
(20320, 20877)

# ord() of second characters
>>> ord('好'), ord('见')
(22909, 35265)

# And with Korean words.
# Pretty < beautiful.
>>> '예쁜' < '아름다운'
False

>>> ord('예'), ord('아')
(50696, 50500)

컨테이너 데이터 타입 비교

컨테이너 데이터 타입(lists, tuples, sets, dicts 등)도 사전순으로 비교해요. 두 컨테이너의 데이터가 같고 데이터 타입도 같으면(lists와 tuples의 경우 순서까지 같아야 해요) 서로 같고, 그렇지 않으면 달라요.

>>> [1, 2] == [1, 2]
True

# But if the data is not in the same order, they are not equal.
>>> [2, 1] == [1, 2]
False

# The same holds true for tuples
>>> (3,4,5) == (5,4,3)
False

# Length is also compared
>>> [1, 2] < [1, 2, 3]
True

# Comparing dicts
>>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 18}
False

>>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 19}
True

비교 연쇄

비교 연산자는 임의로 연쇄할 수 있어요. 표현식의 평가는 left에서 right로 진행된다는 점에 주의해요. 예를 들어 x < y <= z는 x < y and y <= z와 같지만, y는 한 번만 평가돼요. 두 경우 모두 x < y가 False로 판명되면 z는 전혀 평가되지 않아요. 이런 방식을 흔히 short-circuit evaluation이라고 하는데, 표현식의 진릿값이 이미 결정되었다면 평가를 멈춘다는 뜻이에요.

Short circuiting은 다양한 불리언 연산자와 함수, 그리고 파이썬의 비교 연쇄에서도 지원돼요. C, C++, C#, Java를 비롯한 많은 프로그래밍 언어와 달리, 파이썬에서 a < b < c 같은 연쇄 표현식은 전통적인 수학적 해석과 우선순위를 따라요.

>>> x = 2
>>> y = 5
>>> z = 10

>>> x < y < z
True

>>> x < y > z
False

>>> x > y < z
False

동일성 비교

is와 is not 연산자는 객체의 _값_이 아니라 객체의 동일성을 검사해요. 객체의 동일성은 한 번 생성되면 결코 변하지 않으며, id() 함수를 사용해 확인할 수 있어요.

<apple> is <orange>는 id(<apple>) == id(<orange>)일 때 오직 그때만 True로 평가돼요. <apple> is not <orange>는 그 반대를 나타내요.

None과 NotImplemented는 싱글턴이라는 특성 때문에, 항상 is와 is not을 사용해 다른 항목과 비교해야 해요. 이 관례에 대한 자세한 내용은 값 비교와 PEP8에 관한 파이썬 레퍼런스 문서를 참고해요.


# A list of favorite numbers.
>>> my_fav_numbers = [1, 2, 3]

>>> your_fav_numbers = my_fav_numbers

>>> my_fav_numbers is your_fav_numbers
True

# The returned id will differ by system and Python version.
>>> id(my_fav_numbers)
4517478208

# your_fav_numbers is only an alias pointing to the original my_fav_numbers object.
# Assigning a new name does not create a new object.
>>> id(your_fav_numbers)
4517478208


>>> my_fav_numbers is not your_fav_numbers
False

>>> my_fav_numbers is not None
True

>>> my_fav_numbers is NotImplemented
False

멤버십 비교

in과 not in 연산자는 멤버십_을 검사해요. <fish> in <soup>는 <fish>가 <soup>의 멤버일 때(<fish>가 <soup>의 부분집합이거나 <soup> 안에 포함될 때_) True로 평가되고, 그렇지 않으면 False로 평가돼요. <fish> not in <soup>는 그 부정, 즉 <fish> in <soup>의 _반대_를 반환해요.

문자열과 바이트 타입에서 <name> in <fullname>은 <name>이 <fullname>의 부분 문자열일 때 오직 그때만 True예요.


# A set of lucky numbers.
>>> lucky_numbers = {11, 22, 33}
>>> 22 in lucky_numbers
True

>>> 44 in lucky_numbers
False

# A dictionary of employee information.
>>> employee = {'name': 'John Doe', 'id': 67826, 'age': 33, 'title': 'ceo'}

# Checking for the membership of certain keys.
>>> 'age' in employee
True

>>> 33 in employee
False

>>> 'lastname' not in employee
True

# Checking for substring membership
>>> name = 'Super Batman'
>>> 'Bat' in name
True

>>> 'Batwoman' in name
False

객체의 비교 동작은 rich comparison methods를 구현해 사용자 정의할 수 있어요. 더 자세한 내용은 파이썬 튜토리얼: 클래스, 파이썬 클래스와 매직 메서드 (Dan Bader), 특수 메서드 이름을 참고해요.

GitHub에서 편집 링크가 새 창이나 탭에서 열려요

비교 배우기

연습이 잠겨 있어요

비교 개념을 연습하려면 연습 문제 4개를 더 잠금 해제해요