[Python] None, bool, Truthiness
python none, python bool, truthiness, falsy, is None None 비교는
None
None은 값 없음을 나타내는 싱글톤 객체다. 타입은 NoneType. 모든 함수가 명시적 return 없으면 None을 반환한다.
x = None
print(x is None) # True (관례: 항상 is로 비교)
print(type(None)) # <class 'NoneType'>
print(None == False) # False (다른 객체)
print(None == 0) # False
None 비교는 is로
# GOOD
if x is None: ...
if x is not None: ...
# BAD: 일부 객체는 __eq__ 오버로딩으로 None과도 같다고 답할 수 있음
if x == None: ...
PEP 8이 명시한 규칙. NumPy 배열 같은 객체에선 ==가 element-wise 비교가 되어 ValueError까지 일으킨다.
None과 기본값 함정
def append_item(item, items=[]): # WRONG: 기본 인수는 한 번만 평가
items.append(item)
return items
print(append_item(1)) # [1]
print(append_item(2)) # [1, 2] (!?)
# 올바른 패턴
def append_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
bool
bool은 int의 서브클래스로 True == 1, False == 0이다.
python
print(True + 1)
print(isinstance(True, int))
print(True == 1, False == 0)
print(sum([True, False, True, True])) # 카운트로 활용
# bool() 호출 = 진리값 변환
print(bool(0), bool(1), bool(-1))
print(bool(""), bool("0"))
print(bool([]), bool([0]))
print(bool(None)) 결과
2
True
True True
3
False True True
False True
False True
FalseTruthy / Falsy
Python에서 if/while 조건은 객체의 진리값을 검사한다. falsy 값:
NoneFalse- 수치:
0,0.0,0j,Decimal(0),Fraction(0) - 빈 시퀀스/컬렉션:
"",(),[],{},set(),range(0) - 빈 bytes/bytearray:
b"",bytearray() - 사용자 정의 클래스의
__bool__()이False반환 (없으면__len__()0)
나머지는 모두 truthy.
def describe(x):
if x: # Pythonic
return "non-empty / non-zero"
return "empty / zero / None"
# 명확한 의도가 필요하면 비교 명시
if x is None: ... # 정확히 None인지
if len(x) == 0: ... # 빈 시퀀스인지
if x == 0: ... # 정확히 0인지
함정: 0과 빈 컨테이너
def get_or_default(d, key, default="N/A"):
return d.get(key) or default
# 의도: 키 없으면 default
# 실제: 값이 0/빈 문자열/[]이어도 default로 대체됨
get_or_default({"x": 0}, "x") # "N/A" (!!)
# 올바른 코드
def get_or_default(d, key, default="N/A"):
v = d.get(key)
return default if v is None else v
a or b는 a가 falsy면 b. 0이나 ""을 유효값으로 다루는 경우 위험.
bool 연산자: and, or, not
short-circuit 평가하고, bool이 아닌 피연산자도 그대로 반환한다.
python
print(True and "hello") # 'hello'
print(False and "hello") # False (단축)
print("a" or "b") # 'a' (첫 truthy)
print("" or "default") # 'default'
print(not 0) # True
print(not []) # True
# 활용
config_value = user_value or default
errors = errors or []
greeting = name and f"Hello {name}" 결과
hello
False
a
default
True
Trueany / all
any(iter), all(iter)는 truthy 기반 검사. 빈 iterable 처리:
all([]) # True (모든 원소가 참 - 빈 집합은 vacuous truth)
any([]) # False (참인 원소가 없음)
# 컴프리헨션과 결합
if all(x > 0 for x in nums): ...
if any(name.startswith("admin_") for name in users): ...
generator를 받으면 첫 False(any는 첫 True) 발견 즉시 단축.
사용자 클래스의 truthy
class Cart:
def __init__(self):
self.items = []
def __bool__(self):
return bool(self.items) # 비어 있으면 falsy
cart = Cart()
if cart:
checkout()
__bool__이 없으면 __len__()이 사용된다. 둘 다 없으면 항상 truthy.
None 타입 힌트
from typing import Optional
def find_user(uid: int) -> Optional[User]:
"""uid로 유저 조회, 없으면 None"""
...
# Python 3.10+
def find_user(uid: int) -> User | None: ...
Optional[X]는 X | None의 별칭.
💬 댓글