BioPlayground

🧬
목록으로

단락 평가 — Short-circuit Evaluation

Python의 and/or가 실제로 어떻게 평가되는지, 왜 순서가 중요한지, 실전 패턴을 배웁니다.

중급
|
10
|
검증 완료 (2026-07)
단락 평가short-circuitandor조건부 실행
진행률0/12 (0%)

단락 평가 — Short-circuit Evaluation

이 토픽을 마치면

Python의 and/or가 내부적으로 어떻게 동작하는지 이해하고, 단락 평가를 활용한 실전 패턴을 쓸 수 있으며, 순서가 중요한 이유를 설명할 수 있습니다.


단락 평가란

**단락 평가(Short-circuit Evaluation)**는 논리 연산에서 결과가 확정되면 나머지를 평가하지 않는 것입니다.

python
# and: 첫 번째가 False면, 두 번째를 보지 않음
False and print("This never runs") # False
# or: 첫 번째가 True면, 두 번째를 보지 않음
True or print("This never runs") # True

왜 이렇게 동작할까요? 논리적으로 생각하면 당연합니다:

  • and: 하나라도 False면 전체가 False. 첫 번째가 False면 두 번째를 볼 필요 없음
  • or: 하나라도 True면 전체가 True. 첫 번째가 True면 두 번째를 볼 필요 없음

and의 동작

python
# and는 첫 번째 falsy 값을 반환하거나, 마지막 값을 반환
print(0 and 5) # 0 (0은 falsy → 여기서 멈춤)
print("" and "hello") # "" (빈 문자열은 falsy)
print(None and 42) # None (None은 falsy)
print(1 and 5) # 5 (1은 truthy → 다음으로 → 5 반환)
print("hello" and 42) # 42 (둘 다 truthy → 마지막 값)
print(3 and 2 and 1) # 1 (모두 truthy → 마지막 값)
print(3 and 0 and 1) # 0 (0에서 멈춤)

핵심: and첫 번째 falsy 값을 반환합니다. 모두 truthy면 마지막 값을 반환합니다.

Python의 Falsy 값

python
# 이것들은 모두 False로 평가됨
bool(False) # False
bool(0) # False
bool(0.0) # False
bool("") # False
bool(None) # False
bool([]) # False (빈 리스트)
bool({}) # False (빈 딕셔너리)
# 나머지는 전부 True
bool(1) # True
bool("hello") # True
bool([1, 2]) # True

or의 동작

python
# or는 첫 번째 truthy 값을 반환하거나, 마지막 값을 반환
print(0 or 5) # 5 (0은 falsy → 다음으로 → 5 반환)
print("" or "hello") # "hello" (빈 문자열은 falsy → "hello" 반환)
print(None or 42) # 42
print(1 or 5) # 1 (1은 truthy → 여기서 멈춤)
print("hi" or "bye") # "hi" (첫 번째가 truthy)
print(0 or "" or None) # None (모두 falsy → 마지막 값)
print(0 or "" or 42) # 42 (첫 번째 truthy 값)

핵심: or첫 번째 truthy 값을 반환합니다. 모두 falsy면 마지막 값을 반환합니다.


실전 패턴 — 기본값 설정

python
# 사용자가 이름을 안 입력했으면 "Guest" 사용
username = input("Enter name: ") or "Guest"
print(f"Hello, {username}")
# 설정값이 없으면 기본값
config = {}
db_host = config.get("host") or "localhost"
db_port = config.get("port") or 5432

or로 기본값을 설정하는 패턴입니다. 왼쪽이 falsy(빈 문자열, None 등)이면 오른쪽 값이 사용됩니다. JavaScript에서도 동일한 패턴을 자주 씁니다.

주의: 0이나 빈 문자열이 유효한 값인 경우에는 이 패턴이 위험합니다.

python
# Bug: 0도 falsy이므로 기본값이 적용됨
count = 0
result = count or 10 # 10 (의도: 0이어야 함)
# Fix: 명시적 비교
result = count if count is not None else 10 # 0

실전 패턴 — 조건부 실행

python
# and로 조건부 실행 (if 대체)
data = [1, 2, 3]
data and print(f"Data has {len(data)} items") # 출력됨
empty = []
empty and print("This won't print") # 출력 안 됨 (빈 리스트 = falsy)
python
# 안전한 속성 접근
user = {"name": "Hoon", "address": None}
# address가 None이면 .get()을 호출하지 않음
city = user.get("address") and user["address"].get("city")
print(city) # None (and가 None에서 멈춤)

순서가 중요한 이유

단락 평가의 핵심은 비싼 연산을 뒤에 배치하는 것입니다.

python
def is_valid_user(user_id):
"""DB 조회 — 느린 연산"""
print(f"Querying DB for user {user_id}...")
return user_id > 0
def has_permission(user_id, action):
"""권한 확인 — 더 느린 연산"""
print(f"Checking permission for {action}...")
return True
# Good: 빠른 검사를 먼저
user_id = -1
if user_id > 0 and is_valid_user(user_id) and has_permission(user_id, "read"):
print("Access granted")
# Output: (아무것도 출력 안 됨 — user_id > 0이 False이므로 DB 조회 안 함)
# Bad: 느린 검사를 먼저
if is_valid_user(user_id) and user_id > 0:
print("Access granted")
# Output: "Querying DB for user -1..." (불필요한 DB 조회 발생)

에러를 방지하는 데에도 유용합니다:

python
# 리스트가 비어있을 때 인덱싱하면 에러
items = []
# Bad: IndexError 발생
# if items[0] > 10:
# Good: 빈 리스트 체크를 먼저
if items and items[0] > 10:
print("First item is large")
# items가 falsy(빈 리스트)이므로 items[0]은 실행되지 않음

디버깅 시 주의점

단락 평가는 디버깅을 어렵게 만들 수 있습니다.

python
def check_permission(user):
print(f"Checking permission for {user['name']}")
return user.get("role") == "admin"
def validate_input(data):
print(f"Validating: {data}")
return len(data) > 0
user = {"name": "Hoon", "role": "admin"}
data = "hello"
if check_permission(user) or validate_input(data):
print("Granted")
# 출력:
# Checking permission for Hoon
# Granted
# → validate_input은 실행되지 않음! (print도 안 됨)

or에서 첫 번째가 True이면 두 번째 함수는 호출조차 되지 않습니다. 부수 효과(로깅, 카운터 증가)가 있는 함수를 조건식에 넣으면, 실행 여부가 앞의 결과에 따라 달라집니다. 부수 효과가 항상 실행되어야 한다면 조건식 밖에서 먼저 호출하세요.


다른 언어와의 비교

javascript
// JavaScript — 동일한 동작
const name = userInput || "Guest";
const port = config.port || 3000;

// JavaScript ES2020: ?? (Nullish Coalescing)
const count = 0 ?? 10;    // 0 (??는 null/undefined만 체크)
const count2 = 0 || 10;   // 10 (||는 falsy 전체 체크)
python
# Python에는 ?? 연산자가 없음
# 대신 명시적 비교를 사용
count = 0
result = count if count is not None else 10 # 0

JavaScript의 ??(Nullish Coalescing)는 nullundefined만 체크하므로 0이나 빈 문자열이 유효한 값일 때 안전합니다. Python에는 이에 대응하는 연산자가 없으므로, is not None 비교를 명시적으로 써야 합니다.


not과 결합

python
# not은 단락 평가가 아닌 단순 반전
print(not True) # False
print(not 0) # True
print(not "") # True
print(not "hello") # False
python
# 복합 조건에서의 우선순위
# not > and > or
print(not True or False) # False (not True → False, False or False → False)
print(not (True or False)) # False (True or False → True, not True → False)
# 가독성을 위해 괄호를 명시적으로 사용
if (age >= 18) and (not is_banned):
print("Access allowed")

핵심 정리

연산자단락 조건반환 값
and첫 번째가 falsy첫 번째 falsy 값, 또는 마지막 값
or첫 번째가 truthy첫 번째 truthy 값, 또는 마지막 값
not(단락 없음)항상 True 또는 False

단락 평가를 이해하면 세 가지를 얻습니다: 기본값 설정 (x or default), 안전한 접근 (items and items[0]), 성능 최적화 (빠른 조건을 앞에). 대부분의 프로그래밍 언어(JavaScript, Java, C++)도 동일한 규칙을 따르므로, 한 번 익히면 어디서든 적용됩니다.