7. 불리언과 조건
앞선 장들에서 숫자, 문자열, 기본적인 데이터 연산을 다루는 방법을 배웠습니다. 이제 프로그램이 어떻게 결정을 내리는지를 살펴볼 준비가 되었습니다. 이는 프로그램이 다양한 조건에 따라 다르게 반응할 수 있게 해 주는 근본적인 능력입니다. Python에서 의사 결정의 중심에는 불리언 값 (Boolean value) 과 조건 (condition) 이 있습니다.
일상적인 결정을 떠올려 봅시다. "비가 오면 우산을 가져갈 거야." "기온이 30°C 이상이면 에어컨을 켤 거야." 이런 결정은 모두 참이거나 거짓인 조건에 기반합니다. Python도 같은 원리를 사용합니다. 조건을 평가해서 그게 참인지 거짓인지 판단한 다음, 그에 따라 동작합니다.
이 장에서는 불리언 값을 탐구하고, 비교 연산자를 사용해 조건을 만드는 방법을 배우며, Python의 "진릿값(truthiness)" 개념을 이해하고, 복잡한 논리 표현식을 만드는 강력한 기법들을 알아보겠습니다. 이 장을 마치면, 다음 장들에서 배우게 될 if 문과 반복문(loops)을 구성하는 데 필요한 기본 요소들을 익히게 됩니다.
7.1) 불리언 값 True와 False
Python에는 진리값을 나타내는 bool(Boolean의 줄임말)이라는 특별한 데이터 타입이 있습니다. 이 타입은 정확히 두 가지 값만 가질 수 있습니다: True 와 False 입니다. 이 값들이 대문자로 시작한다는 점에 주의해야 합니다. 이는 Python에서 매우 중요합니다. true 나 false 처럼 소문자로 쓰면 Python이 이를 인식하지 못해 에러가 발생합니다.
# boolean_basics.py
# Boolean 변수 만들기
is_sunny = True
is_raining = False
print(is_sunny) # Output: True
print(is_raining) # Output: False
print(type(True)) # Output: <class 'bool'>
print(type(False)) # Output: <class 'bool'>불리언 값은 매우 중요합니다. 왜냐하면 프로그램이 던질 수 있는 모든 예/아니오(yes/no) 질문의 결과를 나타내기 때문입니다. 이 숫자는 10보다 큰가? 이 문자열은 문자 'a'를 포함하는가? 사용자가 로그인되어 있는가? Python의 모든 조건은 결국 True 또는 False 중 하나로 평가됩니다.
7.1.1) 변수와 표현식 속의 불리언
숫자나 문자열을 변수에 저장하는 것처럼 불리언 값도 변수에 저장할 수 있습니다. 이는 프로그램에서 어떤 상태를 추적하고 싶을 때 유용합니다.
# boolean_variables.py
# 상태를 추적하기 위해 Boolean 변수 사용하기
is_logged_in = False
has_permission = True
is_valid_email = True
print("User logged in:", is_logged_in) # Output: User logged in: False
print("Has permission:", has_permission) # Output: Has permission: True
print("Valid email:", is_valid_email) # Output: Valid email: True
# Boolean 변수는 다시 할당할 수 있습니다
is_logged_in = True
print("User logged in:", is_logged_in) # Output: User logged in: True불리언 변수는 보통 is_, has_, can_ 같은 접두사를 붙여 이름을 짓습니다. 이렇게 하면 이 변수가 참/거짓 값을 담고 있다는 사실을 바로 알 수 있어 코드의 목적이 분명해집니다. 이런 네이밍 규칙은 코드 작성자와 코드를 읽는 다른 사람 모두에게 도움이 됩니다.
7.2) 비교 연산자와 기본 조건
True 와 False 로 직접 불리언 값을 만들 수 있지만, 실제 프로그램에서 사용하는 대부분의 불리언 값은 비교 (comparison) 에서 나옵니다. 즉, 값들 사이의 관계를 검사하는 것입니다. Python은 두 값을 비교하고 불리언 결과를 만들어 내는 여러 비교 연산자 (comparison operator) 를 제공합니다.
7.2.1) 여섯 가지 비교 연산자
Python에는 여섯 가지 기본 비교 연산자가 있습니다.
| Operator | 의미 | 예시 | 결과 |
|---|---|---|---|
== | 같다 | 5 == 5 | True |
!= | 같지 않다 | 5 != 3 | True |
< | 작다 | 3 < 5 | True |
> | 크다 | 5 > 3 | True |
<= | 작거나 같다 | 5 <= 5 | True |
>= | 크거나 같다 | 5 >= 3 | True |
이 연산자들을 실제로 사용해 보겠습니다.
# comparison_operators.py
# 숫자 비교하기
x = 10
y = 20
print(x == y) # Output: False
print(x != y) # Output: True
print(x < y) # Output: True
print(x > y) # Output: False
print(x <= y) # Output: True
print(x >= y) # Output: False
# 같은 값을 비교할 때
a = 15
b = 15
print(a == b) # Output: True
print(a <= b) # Output: True
print(a >= b) # Output: True7.2.2) 숫자와 문자열 비교하기
비교 연산자는 정수뿐 아니라 여러 타입의 값에 대해 동작합니다.
# comparing_types.py
# 부동소수점 숫자 비교하기
temperature = 23.5
print(temperature > 20.0) # Output: True
print(temperature == 23.5) # Output: True
# 문자열 비교하기 (알파벳/사전식 순서)
name1 = "Alice"
name2 = "Bob"
print(name1 < name2) # Output: True
print(name1 == name2) # Output: False
# 문자열 비교는 대소문자를 구분합니다
word1 = "Python"
word2 = "python"
print(word1 == word2) # Output: False
# len()을 사용해 문자열 길이 비교하기
print(len(name1) == len(name2)) # Output: False문자열을 비교할 때 Python은 사전식(lexicographic) 순서를 사용합니다. 이는 기본적으로 유니코드 문자 값에 기반한 알파벳 순서입니다. 이 순서에서는 대문자가 소문자보다 먼저 옵니다. 그래서 "Python" 과 "python" 은 같지 않은 것으로 간주됩니다.
7.2.3) 비교 결과를 저장하기
모든 비교의 결과는 불리언 값이므로, 이를 변수에 저장할 수 있습니다.
# storing_comparisons.py
# 나중에 사용하기 위해 비교 결과를 저장하기
age = 25
is_adult = age >= 18
is_senior = age >= 65
is_teenager = 13 <= age <= 19 # 곧 체인 비교에 대해 배웁니다
print("Is adult:", is_adult) # Output: Is adult: True
print("Is senior:", is_senior) # Output: Is senior: False
print("Is teenager:", is_teenager) # Output: Is teenager: False
# 저장된 비교 결과를 계산이나 다른 표현식에 사용하기
price = 100
discount_eligible = price > 50
print("Discount eligible:", discount_eligible) # Output: Discount eligible: True이렇게 비교 결과를 의미 있는 이름의 변수에 저장하면 코드가 훨씬 읽기 쉬워집니다. 프로그램 전체에서 계속 age >= 18 를 반복해서 쓰는 대신, 무엇을 검사하는지 분명히 알려주는 is_adult 변수를 사용할 수 있습니다.
7.3) 비교, 표현식, 그리고 bool() 함수로 얻는 불리언 값
지금까지 비교가 불리언 값을 만든다는 것을 봤습니다. 하지만 Python에서는 이 외에도 bool() 함수를 사용해 다른 타입을 불리언으로 변환하는 등, 불리언 값을 얻는 여러 방법이 있습니다.
7.3.1) bool() 함수
bool() 함수는 어떤 값이든 그에 대응하는 불리언 값으로 변환합니다. 이는 어떤 값이 불리언 문맥에서 참으로 취급될지, 거짓으로 취급될지 명시적으로 확인하고 싶을 때 유용합니다.
# bool_function.py
# 숫자를 Boolean으로 변환하기
print(bool(1)) # Output: True
print(bool(42)) # Output: True
print(bool(-5)) # Output: True
print(bool(0)) # Output: False
print(bool(0.0)) # Output: False
# 문자열을 Boolean으로 변환하기
print(bool("Hello")) # Output: True
print(bool("False")) # Output: True
print(bool("")) # Output: False
# None을 Boolean으로 변환하기
print(bool(None)) # Output: Falsebool() 함수는 특정한 변환 규칙을 따릅니다. 이는 바로 다음 섹션에서 다룰 "진릿값(truthiness)과 falsiness" 에서 자세히 살펴보겠습니다. 지금은 대부분의 값이 True 로 변환되지만, 0, 0.0, 빈 문자열(""), None 같은 몇 가지 특별한 값들은 False 로 변환된다는 점만 기억해 두세요.
7.4) 조건에서의 진릿값(truthiness)과 falsiness
Python의 강력한 기능 중 하나는 진릿값(truthiness) 과 falsiness 개념입니다. Python에서는 True 와 False 뿐 아니라 모든 값이 고유한 불리언 해석을 갖습니다. 즉, 불리언이 기대되는 곳 어디에서나 어떤 값이든 사용할 수 있고, Python은 그 값을 참 또는 거짓으로 간주합니다.
7.4.1) 거짓 같은 값(falsy values): 무엇이 False로 취급되는가
Python에서 다음 값들은 falsy 로 간주됩니다. 즉, 불리언 문맥에서 False 처럼 동작합니다.
- 불리언 값
False자체 - 특별한 값
None - 모든 형태의 숫자 0:
0,0.0,0j(복소수 0) - 빈 시퀀스:
""(빈 문자열),[](빈 리스트),()(빈 튜플) - 빈 매핑:
{}(빈 딕셔너리) - 빈 집합:
set()
이를 bool() 함수로 확인해 보겠습니다.
# falsy_values.py
# 이 값들은 모두 falsy입니다
print("Boolean False:", bool(False)) # Output: Boolean False: False
print("None:", bool(None)) # Output: None: False
print("Zero integer:", bool(0)) # Output: Zero integer: False
print("Zero float:", bool(0.0)) # Output: Zero float: False
print("Empty string:", bool("")) # Output: Empty string: False
print("Empty list:", bool([])) # Output: Empty list: False
print("Empty tuple:", bool(())) # Output: Empty tuple: False
print("Empty dict:", bool({})) # Output: Empty dict: False7.4.2) 참 같은 값(truthy values): 나머지 전부
위에서 언급한 값들을 제외한 모든 값은 Python에서 truthy 로 간주됩니다. 즉, 불리언 문맥에서 True 처럼 동작합니다. 여기에 포함되는 것들은 다음과 같습니다.
- 불리언 값
True자체 - 0이 아닌 모든 숫자(양수와 음수 모두)
- 비어 있지 않은 문자열, 리스트, 튜플, 딕셔너리, 집합
- 대부분의 사용자 정의 객체
# truthy_values.py
# 이 값들은 모두 truthy입니다
print("Boolean True:", bool(True)) # Output: Boolean True: True
print("Positive integer:", bool(42)) # Output: Positive integer: True
print("Negative integer:", bool(-1)) # Output: Negative integer: True
print("Non-zero float:", bool(3.14)) # Output: Non-zero float: True
print("Non-empty string:", bool("Hello")) # Output: Non-empty string: True
print("String 'False':", bool("False")) # Output: String 'False': True
print("String '0':", bool("0")) # Output: String '0': True
print("Non-empty list:", bool([1, 2, 3])) # Output: Non-empty list: True
print("Non-empty tuple:", bool((1,))) # Output: Non-empty tuple: True
print("Non-empty dict:", bool({"a": 1})) # Output: Non-empty dict: True중요한 점: "False" 라는 문자열은 비어 있지 않은 문자열이기 때문에 truthy 입니다. "0" 이라는 문자열도 마찬가지 이유로 truthy 입니다. 실제 불리언 값 False 와 숫자 값 0 만 falsy 입니다.
7.4.3) 진릿값이 중요한 이유
진릿값 개념은 Python에서 매우 자주 접하게 되는 핵심 개념이기 때문에 중요합니다. 8장에서 조건에 따라 결정을 내리는 if 문을 배우게 됩니다. 이 문장들은 명시적인 불리언 비교뿐만 아니라 모든 값을 사용할 수 있습니다. Python이 값의 진릿값을 자동으로 평가해 주기 때문입니다.
진릿값을 이해하면, 컬렉션에 항목이 있는지, 문자열에 내용이 있는지, 선택적(optional) 값이 존재하는지 등을 간결한 코드로 검사할 수 있습니다. 진릿값이 어떻게 유용한지 미리 살짝 살펴보겠습니다(전체 if 문 문법은 8장에서 배웁니다).
# truthiness_preview.py
# bool()로 진릿값을 보여 주기
# (8장에서는 이를 직접 if 문에서 사용할 것입니다)
# 문자열에 내용이 있는지 확인하기
user_input = ""
has_content = bool(user_input)
print("User entered something:", has_content) # Output: User entered something: False
user_input = "Alice"
has_content = bool(user_input)
print("User entered something:", has_content) # Output: User entered something: True
# 리스트에 항목이 있는지 확인하기
shopping_list = []
has_items = bool(shopping_list)
print("Shopping list has items:", has_items) # Output: Shopping list has items: False
shopping_list = ["milk", "eggs", "bread"]
has_items = bool(shopping_list)
print("Shopping list has items:", has_items) # Output: Shopping list has items: True
# 값이 존재하는지(None이 아닌지) 확인하기
optional_value = None
value_exists = bool(optional_value)
print("Value exists:", value_exists) # Output: Value exists: False진릿값을 이해하면 코드가 더 "파이써닉(Pythonic)" 해집니다. 즉, Python의 관습과 관용구를 잘 따르게 됩니다. 숙련된 Python 프로그래머들이 명시적인 비교 없이 값을 그대로 조건에 사용하는 것을 보면, 이들은 진릿값을 활용해 더 간결하고 읽기 쉬운 코드를 작성하고 있는 것입니다.
7.5) 체인 비교와 흔한 불리언 함정
Python은 체인 비교 (chained comparison) 라는 강력한 기능을 제공하는데, 이를 사용하면 특정 조건을 수학 표기법과 더 비슷하게, 그리고 더 읽기 쉽게 표현할 수 있습니다. 하지만 이 기능과 불리언 논리의 다른 측면들은 흔한 실수로 이어지기도 합니다.
7.5.1) 체인 비교
수학에서 "10 < x < 20" 이라고 써서 x가 10과 20 사이에 있다는 뜻을 표현하곤 합니다. Python에서는 이 표현을 그대로 쓸 수 있습니다.
# chained_comparisons.py
# 값이 어떤 범위에 속하는지 확인하기
x = 15
# 수학적인 방식(체인 비교)
in_range = 10 < x < 20
print("x is between 10 and 20:", in_range) # Output: x is between 10 and 20: True
# 이는 두 개의 비교를 결합한 것과 같습니다
# ('and'에 대해서는 9장에서 배웁니다)
in_range = (10 < x) and (x < 20)
print("x is between 10 and 20:", in_range) # Output: x is between 10 and 20: True
# 범위 밖의 값으로 테스트하기
y = 25
in_range = 10 < y < 20
print("y is between 10 and 20:", in_range) # Output: y is between 10 and 20: False
# 경계값으로 테스트하기
z = 10
in_range = 10 < z < 20
print("z is between 10 and 20:", in_range) # Output: z is between 10 and 20: False
# <= 와 >= 를 사용해 경계를 포함하기
in_range_inclusive = 10 <= z <= 20
print("z is between 10 and 20 (inclusive):", in_range_inclusive) # Output: z is between 10 and 20 (inclusive): True체인 비교는 인접한 항목 쌍을 순서대로 평가하는 방식으로 동작합니다. 10 < x < 20 이라는 표현은 (10 < x) and (x < 20) 으로 평가됩니다. 이 체인에 있는 모든 비교가 참이어야 전체 표현이 참이 됩니다.
비교는 두 개보다 더 많이 연결할 수도 있습니다.
# multiple_chains.py
# 여러 비교를 체인으로 연결하기
a = 5
b = 10
c = 15
d = 20
# 값들이 오름차순인지 확인하기
ascending = a < b < c < d
print("Values are in ascending order:", ascending) # Output: Values are in ascending order: True체인 비교가 어떻게 동작하는지 시각적으로 표현해 보면 다음과 같습니다.
7.5.2) 흔한 함정: 대입과 비교
초보자가 가장 자주 저지르는 실수 중 하나는 비교해야 할 때 대입(=)을 사용하는 것입니다. 비교에는 == 를 사용해야 합니다.
# assignment_vs_comparison_pitfall.py
x = 10
# 이것은 비교가 아니라 대입입니다
# x에 20을 대입하지, x를 20과 비교하지 않습니다
# x = 20 # 이렇게 하면 x는 20으로 바뀝니다
# 이것이 비교입니다
result = (x == 20) # x가 20과 같은지 확인합니다
print("x equals 20:", result) # Output: x equals 20: False
print("x is now:", x) # Output: x is now: 10
# 8장에서 배우겠지만, 조건에서 = 를 사용하면 에러가 발생합니다
# if x = 20: # SyntaxError: invalid syntax
# print("This won't work")
# 올바른 비교
# 8장에서는 이렇게 쓸 것입니다: if x == 10:
result = x == 10
print("x equals 10:", result) # Output: x equals 10: TruePython은 if 문(8장에서 배울 예정) 안에서 이런 실수를 하면 = 사용 시 SyntaxError 를 발생시켜 이를 방지해 줍니다. 하지만 다른 문맥에서는 == 를 써야 할 곳에 잘못 = 를 쓰면, 찾기 어려운 미묘한 버그가 생길 수 있습니다.
7.5.3) 흔한 함정: 부동소수점 비교
부동소수점 숫자를 비교할 때는 정밀도 문제에 주의해야 합니다.
# floating_point_comparison.py
# 부동소수점 연산은 정밀도 문제를 가질 수 있습니다
result = 0.1 + 0.2
print("0.1 + 0.2 =", result) # Output: 0.1 + 0.2 = 0.30000000000000004
# 직접 비교는 기대와 다르게 동작할 수 있습니다
is_equal = (result == 0.3)
print("Result equals 0.3:", is_equal) # Output: Result equals 0.3: False
# 실제 값은 0.3과 매우 가깝지만 정확히 0.3은 아닙니다
print("Difference:", result - 0.3) # Output: Difference: 5.551115123125783e-17
# 부동소수점 비교에는 작은 허용 오차를 두는 것이 좋습니다
tolerance = 0.0001
is_close = abs(result - 0.3) < tolerance
print("Result is close to 0.3:", is_close) # Output: Result is close to 0.3: True
# Python 3.5+에는 이를 위한 math.isclose()가 있습니다
# 모듈 임포트에 대해서는 23장에서 배웁니다
# import math
# is_close = math.isclose(result, 0.3)이 문제는 컴퓨터가 부동소수점 숫자를 이진법으로 저장하기 때문입니다. 0.1 같은 일부 십진수는 이진법으로 정확히 표현할 수 없습니다. 이런 숫자들로 연산을 하면 아주 작은 반올림 오차가 누적됩니다. 대부분의 실제 용도에서는 이 오차가 무시해도 될 정도로 작지만, 직접적인 동등 비교는 예상과 다르게 실패할 수 있습니다.
7.6) 정수(1과 0)로서의 불리언과, 왜 산술에 사용하면 안 되는가
흥미로운 사실 하나: Python에서 True 와 False 는 실제로 정수의 특별한 경우입니다. True 는 1 과 같고, False 는 0 과 같습니다. 이것은 Python 설계에서 비롯된 역사적 유산이지만, 몇 가지 흥미로운 결과를 낳습니다. 이 관계를 이해하면 혼란을 피할 수 있지만, 실제 코드에서 이를 직접 활용할 일은 거의 없습니다.
7.6.1) 불리언은 정수이다
타입을 확인하고 정수 연산을 해 보면 불리언이 정수라는 것을 확인할 수 있습니다.
# booleans_as_integers.py
# Boolean은 정수의 하위 타입입니다
print(isinstance(True, int)) # Output: True
print(isinstance(False, int)) # Output: True
# True는 1과 같고, False는 0과 같습니다
print(True == 1) # Output: True
print(False == 0) # Output: True
print(True == 2) # Output: False
# Boolean을 산술 연산에 사용할 수 있습니다(하지만 그러지 않는 것이 좋습니다!)
result = True + True
print("True + True =", result) # Output: True + True = 2
result = True + False
print("True + False =", result) # Output: True + False = 1
result = False * 100
print("False * 100 =", result) # Output: False * 100 = 0
# Boolean은 리스트 인덱스로도 사용할 수 있습니다
items = ["first", "second", "third"]
print(items[False]) # Output: first
print(items[True]) # Output: secondisinstance() 함수는 값이 특정 타입의 인스턴스인지 확인합니다. isinstance(True, int) 를 호출하면, bool 타입이 int 타입의 서브클래스이기 때문에 Python은 True 를 반환합니다.
7.6.2) 불리언 산술을 피해야 하는 이유
Python이 불리언을 산술 연산에 사용할 수 있도록 허용하긴 하지만, 그렇게 사용하는 것은 피해야 합니다. 불리언을 숫자로 쓰면 코드가 혼란스럽고 이해하기 어려워집니다. 불리언과 정수 사이의 관계는 대부분 역사적인 세부사항일 뿐이며, 알고만 있으면 되고 직접 활용할 일은 거의 없습니다.
왜 불리언 산술이 문제를 일으키는지 살펴보겠습니다.
# boolean_arithmetic_problems.py
# 혼란스러운 코드의 예
count = 0
has_error = True
has_warning = False
# 이렇게 해도 동작은 하지만 혼란스럽습니다
total = count + has_error + has_warning
print("Total:", total) # Output: Total: 1
# 이게 무슨 의미일까요? 명확하지 않습니다!
# 더 나은 접근법: 의도를 명시적으로 드러내기
# if-else 표현식에 대해서는 10장에서 배웁니다.
error_count = 1 if has_error else 0
warning_count = 1 if has_warning else 0
total = count + error_count + warning_count
print("Total:", total) # Output: Total: 1이 규칙의 유일한 흔한 예외는 컬렉션 안에서 True 값이 몇 개 있는지 셀 때입니다.
# counting_trues.py
# 몇 개의 조건이 True인지 세기
conditions = [True, False, True, True, False]
# 이 코드는 의도가 분명하기 때문에 허용할 만합니다
true_count = sum(conditions)
print("Number of true conditions:", true_count) # Output: Number of true conditions: 3
# sum() 이 값들을 모두 더하기 때문입니다
# True는 1로, False는 0으로 처리됩니다
# 따라서 sum([True, False, True, True, False]) = 1 + 0 + 1 + 1 + 0 = 3이 경우, 불리언 리스트에 sum() 을 사용하는 것은 널리 쓰이는 Python 관용구입니다. "몇 개의 조건이 참인지 세기" 라는 의도가 문맥상 분명히 드러나기 때문입니다.
7.6.3) 타입 변환에서의 불리언
불리언이 정수이기 때문에, 이를 정수로 명시적으로 변환하는 것은 중복된 작업입니다.
# boolean_conversion.py
# Boolean을 정수로 변환하기(불필요한 작업)
value = True
int_value = int(value)
print("Integer value:", int_value) # Output: Integer value: 1
print("Are they equal?", value == int_value) # Output: Are they equal? True
# 하지만 정수를 Boolean으로 변환하는 것은 유용합니다
number = 0
bool_value = bool(number)
print("Boolean value:", bool_value) # Output: Boolean value: False
number = 42
bool_value = bool(number)
print("Boolean value:", bool_value) # Output: Boolean value: Trueint() 로 불리언을 정수로 변환하는 것은 불필요합니다. 불리언은 이미 정수처럼 동작하기 때문입니다. 반면, 정수(또는 다른 타입)를 bool() 로 불리언으로 변환하는 것은, 진릿값을 명시적으로 확인하고 싶을 때 유용합니다.
7.6.4) 역사적 이유
불리언이 Python에서 정수인 이유는 역사적 배경에 있습니다. 초창기 Python(2.3 이전 버전)에는 별도의 Boolean 타입이 없었습니다. 프로그래머들은 참을 나타내기 위해 1, 거짓을 나타내기 위해 0 을 사용했습니다. 이후 bool 타입이 추가되었을 때, 기존 코드와의 하위 호환성을 유지하기 위해 bool 을 int 의 서브클래스로 설계했습니다.
오늘날에는 True 와 False 를 무엇보다도 불리언 값으로 생각해야 합니다. 이 값들이 1 과 0 과 어떤 관계를 갖는지는 구현상의 세부사항일 뿐이며, 예상치 못한 상황에서 그것을 마주칠 때를 제외하고는 크게 신경 쓸 필요가 없습니다.
7.7) 조건에서 in과 not in 사용하기
in 과 not in 연산자는 어떤 값이 컬렉션 안에 존재하는지, 즉 멤버십(membership) 을 검사합니다. 이 연산자들은 특히 문자열, 리스트, 기타 컬렉션을 다룰 때 읽기 좋은 조건을 만드는 데 매우 유용합니다.
7.7.1) 문자열에서의 멤버십 검사
in 연산자는 한 문자열이 다른 문자열 안에 포함되어 있는지를 검사합니다.
# string_membership.py
# 문자열에 특정 부분 문자열이 존재하는지 확인하기
text = "Python programming is fun"
# 'in' 을 사용해 부분 문자열 확인하기
has_python = "Python" in text
print("Contains 'Python':", has_python) # Output: Contains 'Python': True
has_java = "Java" in text
print("Contains 'Java':", has_java) # Output: Contains 'Java': False
# 대소문자를 구분하는 매칭
has_python_lower = "python" in text
print("Contains 'python':", has_python_lower) # Output: Contains 'python': False
# 'not in' 을 사용해 포함되지 않았는지 확인하기
has_no_java = "Java" not in text
print("Does not contain 'Java':", has_no_java) # Output: Does not contain 'Java': Truein 연산자는 대소문자를 구분하는 검색을 수행합니다. 대소문자를 구분하지 않는 검색이 필요하다면, 두 문자열을 같은 대소문자로 변환한 뒤 비교하면 됩니다.
# case_insensitive_search.py
text = "Python Programming"
# 대소문자를 구분하는 검색(매치되지 않음)
result = "python" in text
print("Contains 'python':", result) # Output: Contains 'python': False
# 대소문자를 구분하지 않는 검색(둘 다 소문자로 변환)
result = "python" in text.lower()
print("Contains 'python' (case-insensitive):", result) # Output: Contains 'python' (case-insensitive): True
# 원본 문자열은 바뀌지 않습니다
print("Original text:", text) # Output: Original text: Python Programming7.7.2) 리스트에서의 멤버십 검사
in 연산자는 리스트에도 사용할 수 있습니다(리스트에 대해서는 14장에서 자세히 배웁니다).
# list_membership.py
# 리스트에 특정 값이 존재하는지 확인하기
numbers = [1, 2, 3, 4, 5]
has_three = 3 in numbers
print("List contains 3:", has_three) # Output: List contains 3: True
has_ten = 10 in numbers
print("List contains 10:", has_ten) # Output: List contains 10: False
# 'not in' 사용하기
missing_ten = 10 not in numbers
print("List does not contain 10:", missing_ten) # Output: List does not contain 10: True
# 리스트 안의 문자열에도 동작합니다
fruits = ["apple", "banana", "cherry"]
has_banana = "banana" in fruits
print("List contains 'banana':", has_banana) # Output: List contains 'banana': True
has_grape = "grape" in fruits
print("List contains 'grape':", has_grape) # Output: List contains 'grape': False7.7.3) range와 함께 사용하는 멤버십 검사
range 객체에도 in 을 사용할 수 있습니다(range 에 대해서는 12장에서 배웁니다).
# range_membership.py
# 숫자가 range 안에 있는지 확인하기
age = 25
# range와 함께 'in' 사용하기
is_adult = age in range(18, 100)
print("Is adult:", is_adult) # Output: Is adult: True
# 하지만 숫자 범위에는 비교 연산자가 더 효율적입니다
is_adult = 18 <= age < 100
print("Is adult:", is_adult) # Output: Is adult: True
# 'in' 과 range는 특정한 수열에 대해 유용합니다
valid_ages = range(18, 66) # 근로 가능 연령대
is_working_age = age in valid_ages
print("Is working age:", is_working_age) # Output: Is working age: True7.7.4) not in 연산자
not in 연산자는 in 의 반대입니다. 값이 컬렉션에 없을 때 True 를 반환합니다.
# not_in_operator.py
# 더 읽기 좋은 논리를 위해 'not in' 사용하기
allowed_users = ["alice", "bob", "charlie"]
current_user = "eve"
# 'not in' 을 사용하면 더 읽기 쉽습니다
is_unauthorized = current_user not in allowed_users
print("User is unauthorized:", is_unauthorized) # Output: User is unauthorized: True
# 필요한 필드가 빠졌는지 확인하기
provided_fields = ["name", "email"]
# 빠진 필드 찾기
missing_name = "name" not in provided_fields
missing_email = "email" not in provided_fields
missing_password = "password" not in provided_fields
print("Missing name:", missing_name) # Output: Missing name: False
print("Missing email:", missing_email) # Output: Missing email: False
print("Missing password:", missing_password) # Output: Missing password: Truein 과 not in 연산자는 조건을 더 읽기 쉽고 표현력 있게 만들어 줍니다. 복잡한 비교를 작성하는 대신, "이 값이 이 컬렉션 안에 있는가?" 를 그대로 코드로 표현할 수 있어, 문제를 생각하는 방식과 코드 표현이 잘 맞아떨어집니다.
이 장에서는 Python에서 불리언 값과 조건의 기초를 배웠습니다. 이제 여러분은 다음 내용을 이해하게 되었습니다.
- 의사 결정에서 중요한 불리언 값
True와False - 조건을 만들기 위한 비교 연산자 (
==,!=,<,>,<=,>=) - 값을 불리언으로 변환하는
bool()함수 - 모든 값을 참 또는 거짓으로 해석하는 Python의 진릿값(truthiness)과 falsiness 개념
- 범위를 읽기 좋게 검사하는 체인 비교
- 불리언을 다룰 때 피해야 할 흔한 함정들
- 불리언과 정수의 관계(그리고 왜 불리언을 산술에 사용하면 안 되는지)
in과not in연산자를 사용한 멤버십 검사
이 개념들은 다음 장들에서 배울 제어 흐름 구조의 기초를 이룹니다. 8장에서는 불리언 표현식을 if 문에 사용해, 프로그램이 다양한 조건에 따라 다르게 반응하도록 만들 것입니다. 9장에서는 and, or, not 같은 논리 연산자를 사용해 여러 조건을 결합하는 방법을 배우게 됩니다. 그리고 10장과 11장에서는 조건을 사용해, 동작을 반복하는 반복문을 제어하는 방법을 배우게 됩니다.
불리언과 조건을 이해하는 것은, 프로그램이 결정을 내리고, 입력을 검증하며, 다양한 상황에 적절히 반응하도록 만드는 데 필수적입니다. 이 개념들을 연습해 보면, Python에서 의사 결정을 구현하는 일이 점점 자연스럽고 직관적으로 느껴질 것입니다.