Truthy/Falsy와 is vs ==
이 토픽을 마치면
Python에서 어떤 값이 조건문에서 True/False로 평가되는지 알 수 있고, is와 ==를 올바르게 구분해서 사용할 수 있습니다.
Truthy와 Falsy
Python의 if문은 True/False만 받는 것이 아닙니다. 어떤 값이든 조건으로 사용할 수 있습니다:
if "hello": print("실행됨") # 실행됨!
if 0: print("실행 안 됨") # 실행 안 됨Python은 모든 값을 Truthy(참으로 취급)와 Falsy(거짓으로 취급)로 나눕니다.
Falsy 값 — 외우면 끝
Falsy인 값은 정해져 있습니다. 나머지는 전부 Truthy입니다:
# 이것들이 Falsy (False로 평가)FalseNone0 # 정수 00.0 # 실수 0"" # 빈 문자열[] # 빈 리스트{} # 빈 딕셔너리set() # 빈 세트# 확인해보기values = [False, None, 0, 0.0, "", [], {}, set()]for v in values: print(f"{str(v):10} → {bool(v)}")# False → False# None → False# 0 → False# 0.0 → False# → False# [] → False# {} → False# set() → False핵심 규칙: "비어있거나 0이면 Falsy". 이것만 기억하면 됩니다.
실무 패턴 — 빈 값 체크
Truthy/Falsy를 활용하면 코드가 간결해집니다:
# 리스트가 비어있는지 확인items = []
# 이렇게 쓸 필요 없음if len(items) > 0: print("있음")
# 이렇게 쓰면 됨if items: print("있음")# 문자열이 비어있는지 확인name = ""
if name: print(f"안녕, {name}")else: print("이름을 입력해주세요")# None 체크와 기본값def greet(name=None): name = name or "손님" return f"안녕하세요, {name}"
print(greet()) # "안녕하세요, 손님"print(greet("철수")) # "안녕하세요, 철수"or 연산자는 왼쪽이 Falsy면 오른쪽을 반환합니다. 기본값 패턴으로 자주 씁니다.
== — 값이 같은가
==는 두 값이 동등한지 비교합니다:
a = [1, 2, 3]b = [1, 2, 3]
print(a == b) # True — 내용이 같으니까두 리스트는 별개의 객체이지만, 담고 있는 값이 같으므로 ==는 True입니다.
print(1 == 1.0) # True — 숫자 값이 같으면print("abc" == "abc") # Trueprint([1] == [1]) # Trueis — 같은 객체인가
is는 두 변수가 메모리에서 같은 객체를 가리키는지 비교합니다:
a = [1, 2, 3]b = [1, 2, 3]c = a
print(a == b) # True — 값이 같음print(a is b) # False — 다른 객체print(a is c) # True — 같은 객체를 가리킴a와 b는 내용은 같지만 서로 다른 리스트 객체입니다. c = a는 같은 리스트를 가리키므로 is가 True입니다.
# id()로 확인 가능print(id(a)) # 140234567890print(id(b)) # 140234567920 (다른 주소)print(id(c)) # 140234567890 (a와 같은 주소)None 비교 — is를 써야 하는 이유
result = None
# ✅ 올바른 방법if result is None: print("결과 없음")
# ❌ 권장하지 않는 방법if result == None: print("결과 없음")None은 Python 전체에서 단 하나의 객체입니다. is로 비교하면 "이것이 바로 그 None 객체인가?"를 직접 확인합니다.
==는 클래스가 __eq__ 메서드를 오버라이드하면 예상과 다르게 동작할 수 있습니다:
class Tricky: def __eq__(self, other): return True # 무엇과 비교해도 True
t = Tricky()print(t == None) # True — 위험!print(t is None) # False — 안전PEP 8(Python 공식 스타일 가이드)에서도 None 비교는 is를 사용하라고 명시합니다.
정수 캐싱 트랩
a = 256b = 256print(a is b) # True — CPython이 -5~256을 미리 캐싱
a = 257b = 257print(a is b) # False — 범위 밖이라 별도 객체 생성CPython은 작은 정수(-5~256)를 미리 만들어놓고 재사용합니다. 이 범위 안에서는 is가 True지만, 밖에서는 False입니다. 이것이 값 비교에 is를 쓰면 안 되는 이유입니다. is는 오직 None, True, False 비교에만 사용합니다.
# 문자열에서도 비슷한 현상a = "hello"b = "hello"print(a is b) # True — 인터닝(interning) 발동
a = "hello world!"b = "hello world!"print(a is b) # False — 공백+특수문자 포함 시 인터닝 안 됨함수 매개변수의 기본값과 None
# ❌ 위험한 패턴def add_item(item, items=[]): items.append(item) return items
print(add_item("a")) # ["a"]print(add_item("b")) # ["a", "b"] — 이전 호출의 결과가 남아있음!
# ✅ 안전한 패턴def add_item(item, items=None): if items is None: items = [] items.append(item) return items가변 객체(리스트, 딕셔너리)를 기본값으로 쓰면 모든 호출이 같은 객체를 공유합니다. None을 기본값으로 쓰고 함수 안에서 새 객체를 만드는 것이 Python의 표준 패턴입니다.
bool()과 Truthy/Falsy 활용
# 빈 값 검증을 간결하게data = {"name": "철수", "email": "", "phone": None}
# ❌ 길고 반복적if data["name"] is not None and data["name"] != "": print("name 있음")
# ✅ Truthy/Falsy 활용if data["name"]: print("name 있음")
# 유효한 값만 필터링values = [0, "", None, "hello", [], [1, 2], False, 42]valid = list(filter(None, values))print(valid) # ["hello", [1, 2], 42]filter(None, iterable)은 Falsy 값을 모두 제거합니다. 데이터 정제에서 자주 쓰이는 패턴입니다.
정리
| 비교 | 의미 | 사용 시점 |
|---|---|---|
== | 값이 같은가 | 일반적인 값 비교 |
is | 같은 객체인가 | None, True, False 비교 |
!= | 값이 다른가 | 일반적인 불일치 확인 |
is not | 다른 객체인가 | is not None |
# 이 패턴들을 기억하세요if x is None: # None 체크if x is not None: # None이 아닌지 체크if items: # 비어있지 않은지 (Truthy)if not items: # 비어있는지 (Falsy)any()와 all() — 컬렉션의 Truthy 활용
scores = [85, 92, 0, 78, 95]
print(any(scores)) # True — 하나라도 Truthy (0이 아닌 것 존재)print(all(scores)) # False — 0이 Falsy
# 조건식과 함께print(any(s >= 90 for s in scores)) # True — 90 이상이 있는가print(all(s >= 60 for s in scores)) # False — 모두 60 이상인가any()와 all()은 내부적으로 Truthy/Falsy 판별을 사용합니다. 조건을 간결하게 표현할 때 유용합니다.
단축 평가(Short-circuit) 활용
# or — 첫 Truthy를 반환 (없으면 마지막 값)name = user_input or "기본이름"
# and — 첫 Falsy를 반환 (없으면 마지막 값)result = data and data[0] # data가 비어있으면 [] 반환, 아니면 첫 원소or와 and는 불리언을 반환하는 게 아니라, Truthy/Falsy 판단을 멈춘 시점의 값을 반환합니다. 기본값 설정이나 안전한 접근 패턴에 자주 쓰입니다.
==와 is의 차이를 모르면 찾기 어려운 버그가 생깁니다. 특히 None 비교에서 == 대신 is를 쓰는 습관은 Python 코드 품질의 기본입니다.