
파이썬에는 문자열에 변수를 끼워 넣는 방법이 4가지나 있습니다. % 연산자(C 스타일), str.format(), f-string, 그리고 최근에 추가된 t-string까지. 옛날 코드베이스에서는 %s, %d를 자주 볼 수 있고, 중간 세대 코드에서는 "{name}".format(name=...)이 흔해요. 문제는 앞의 두 방식이 읽기도 어렵고, 수정하기도 번거롭고, 버그도 만들기 쉽다는 겁니다.
Python 3.6부터 들어온 f-string은 사실상 이 모든 문제를 한 방에 정리한 문법이에요. 이제 새로 작성하는 코드에서 %나 .format()을 쓸 이유는 거의 없습니다.
name = "지훈"
age = 30
city = "서울"
# ① C 스타일 — 순서 맞추기 고역, 값 바뀌면 다시 맞춰야 함
msg = "%s(%d세)은 %s에 삽니다" % (name, age, city)
# 값 하나 더 넣고 싶을 때 튜플 순서 다 맞춰야 함
msg = "%s(%d세, %s 거주)님 환영합니다. %s님!" % (name, age, city, name) # name 두 번 중복
# ② 딕셔너리로 풀면 덜 아프지만 번잡함
msg = "%(name)s은 %(age)d세입니다" % {"name": name, "age": age}
# ③ str.format — 좀 낫지만 여전히 두 번 쓰는 느낌
msg = "{name}은 {age}세입니다".format(name=name, age=age)
% 방식은 좌우 순서·개수·타입이 모두 일치해야 하고, 값 하나만 살짝 바꾸려 해도 튜플 전체를 다시 조립해야 합니다. 같은 값을 여러 번 쓰면 튜플에 중복으로 넣어야 하고요. str.format은 키워드 인자로 가독성이 좀 나아지지만, 변수명을 두 번 쓰는 중복({name}과 name=name)이 여전히 거슬립니다.
name = "지훈"
age = 30
city = "서울"
# f-string: 변수 이름을 그대로 문자열 안에 쓴다
msg = f"{name}({age}세)은 {city}에 삽니다"
# 식(expression)도 그대로 들어간다
msg = f"{name}님은 내년에 {age + 1}세가 됩니다"
# 포매팅 스펙도 동일하게 지원
pi = 3.141592
msg = f"파이는 {pi:.2f}입니다" # 3.14
msg = f"가격: {1234567:,}원" # 1,234,567원
msg = f"{0.85:.1%}" # 85.0%
# 디버깅용 = 표기 (Python 3.8+) — 변수명과 값을 한꺼번에
x, y = 10, 20
print(f"{x=}, {y=}") # x=10, y=20
f-string의 핵심은 변수 이름을 문자열 안에 바로 쓴다는 점입니다. 중복이 사라지고, {age + 1}처럼 식도 그대로 평가돼요. :.2f, :,, :% 같은 포매팅 스펙도 기존 방식과 똑같이 쓸 수 있어서 손해 보는 것도 없습니다.
디버깅할 때 유용한 f"{x=}" 표기법도 꼭 기억하세요. print(f"{user=}") 한 줄이면 user=<User object>처럼 변수명과 값을 같이 찍어주니까, 찍어볼 변수가 많을 때 엄청 편합니다.
% 스타일, str.format(), f-string 중에서 새 코드는 무조건 f-string이 정답입니다.{a + b}, {user.name.upper()}).:.2f, :,, :>10, :% 등)이 f-string에서도 그대로 동작합니다.f"{x=}" 형태는 디버깅 로그 찍을 때 특히 유용합니다(Python 3.8+).{{, }}로 이스케이프하세요.사실상 모든 곳입니다. 로깅 메시지, 사용자에게 보여줄 에러 메시지, SQL 쿼리 생성(단, 사용자 입력으로 쿼리 만들 땐 f-string 대신 파라미터 바인딩 쓰세요 — SQL 인젝션 위험), API 응답 포매팅, CLI 출력 등. 특히 데이터 분석 리포트나 Slack 알림봇 만들 때 f"오늘 신규 가입 {new_users:,}명 (전일 대비 {growth:+.1%})" 같은 한 줄이면 깔끔한 출력이 완성됩니다.
한 가지 유의점은 로깅 라이브러리에서는 f-string이 항상 최선은 아니라는 점이에요. logger.info(f"user={user.name}")보다 logger.info("user=%s", user.name) 쪽이 로그 레벨에 따라 문자열 포매팅 자체를 건너뛸 수 있어 성능상 유리합니다. 고빈도 로그에서만 신경 쓰면 되고, 평범한 애플리케이션에서는 f-string이 가독성 면에서 압도적이니 편하게 쓰세요.