“이름: 홍길동, 나이: 25세” 같은 문자열을 만들 때마다 +와 str()로 고생하셨나요? f-string 하나면 모든 문제가 해결됩니다! Python 3.6부터 추가된 가장 강력하고 직관적인 문자열 포맷팅 방법을 배워봅시다. 한 번 배우면 다시는 복잡한 문자열 연결로 돌아가지 않을 겁니다! (25분 완독 ⭐⭐)
🎯 오늘의 학습 목표
📚 사전 지식
🎯 학습 목표 1: f-string이 무엇인지 이해하기
f-string이란?
f-string = Formatted String Literal의 약자로, 문자열 안에 변수나 표현식을 쉽게 삽입하는 방법 (Python 3.6+)
문자열 앞에 f나 F를 붙이고, 중괄호 {}로 변수나 표현식을 감싸면 자동으로 값이 삽입됩니다.
기존 방법의 문제점
1
2
3
4
5
6
7
8
9
10
11
12
| name = "홍길동"
age = 25
score = 95.5
# ❌ 방법 1: + 연결 (복잡하고 에러 발생 쉬움)
message = name + "의 나이는 " + str(age) + "세이고, 점수는 " + str(score) + "점입니다."
# ❌ 방법 2: % 포맷팅 (구식, 가독성 떨어짐)
message = "%s의 나이는 %d세이고, 점수는 %.1f점입니다." % (name, age, score)
# ❌ 방법 3: .format() (장황함)
message = "{}의 나이는 {}세이고, 점수는 {:.1f}점입니다.".format(name, age, score)
|
f-string의 장점
1
2
3
4
5
6
7
| name = "홍길동"
age = 25
score = 95.5
# ✅ f-string (간단하고 직관적!)
message = f"{name}의 나이는 {age}세이고, 점수는 {score:.1f}점입니다."
print(message) # 홍길동의 나이는 25세이고, 점수는 95.5점입니다.
|
f-string이 최고인 이유
| 특징 | 설명 |
| 가독성 | 변수가 어디에 들어갈지 한눈에 보임 |
| 간결성 | 타입 변환 불필요, 자동으로 문자열화 |
| 속도 | 다른 방법보다 빠름 (컴파일 시점 최적화) |
| 표현식 | 변수뿐 아니라 계산식, 함수 호출도 가능 |
🎯 학습 목표 2: f-string 기본 사용법 익히기
기본 문법
변수 삽입
1
2
3
4
5
6
7
8
9
10
11
| name = "홍길동"
age = 25
city = "서울"
# f를 붙이고 {}로 변수 감싸기
print(f"이름: {name}")
print(f"나이: {age}")
print(f"도시: {city}")
# 여러 변수 한 번에
print(f"{name}님은 {city}에 사는 {age}세입니다.")
|
표현식 사용
1
2
3
4
5
6
7
8
9
10
11
| a = 10
b = 20
# 계산식도 가능
print(f"{a} + {b} = {a + b}") # 10 + 20 = 30
print(f"{a} * {b} = {a * b}") # 10 * 20 = 200
# 함수 호출도 가능
name = "python"
print(f"대문자: {name.upper()}") # 대문자: PYTHON
print(f"길이: {len(name)}") # 길이: 6
|
숫자 포맷팅
소수점 자리수 지정
| 포맷 | 의미 | 예시 |
{num:.2f} | 소수점 2자리 | 3.14 |
{num:.4f} | 소수점 4자리 | 3.1416 |
{num:.0f} | 정수로 (반올림) | 3 |
1
2
3
4
5
6
7
8
9
10
| pi = 3.141592653589793
print(f"{pi:.2f}") # 3.14 (소수점 2자리)
print(f"{pi:.4f}") # 3.1416 (소수점 4자리)
print(f"{pi:.0f}") # 3 (정수로)
# 퍼센트 표시
ratio = 0.856
print(f"{ratio:.1%}") # 85.6%
print(f"{ratio:.2%}") # 85.60%
|
천 단위 구분 (숫자 가독성 향상)
1
2
3
4
5
6
7
8
| price = 1234567
print(f"{price:,}원") # 1,234,567원
print(f"{price:,.2f}원") # 1,234,567.00원
# 큰 숫자도 읽기 쉽게
population = 51780579
print(f"인구: {population:,}명") # 인구: 51,780,579명
|
정렬과 패딩
문자열 정렬
| 기호 | 정렬 방식 | 예시 |
< | 왼쪽 정렬 | {text:<10} |
> | 오른쪽 정렬 | {text:>10} |
^ | 가운데 정렬 | {text:^10} |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| name1 = "홍길동"
name2 = "김"
name3 = "이영희"
# 왼쪽 정렬 (기본)
print(f"{name1:<10}|") # 홍길동 |
print(f"{name2:<10}|") # 김 |
# 오른쪽 정렬
print(f"{name1:>10}|") # 홍길동|
print(f"{name2:>10}|") # 김|
# 가운데 정렬
print(f"{name1:^10}|") # 홍길동 |
print(f"{name3:^10}|") # 이영희 |
|
숫자 정렬 (0으로 채우기)
1
2
3
4
5
6
7
8
9
10
11
12
| # 숫자 앞을 0으로 채우기
number = 42
print(f"{number:05d}") # 00042
# 실전 예: 파일 번호 생성
for i in range(1, 11):
filename = f"file_{i:03d}.txt"
print(filename)
# file_001.txt
# file_002.txt
# ...
# file_010.txt
|
🎯 학습 목표 3: f-string 고급 기능 활용하기
날짜와 시간 포맷팅
1
2
3
4
5
6
7
8
9
10
11
12
13
| from datetime import datetime
now = datetime.now()
# 날짜 포맷팅
print(f"현재 시각: {now:%Y-%m-%d %H:%M:%S}")
# 현재 시각: 2024-03-16 14:30:45
print(f"오늘: {now:%Y년 %m월 %d일}")
# 오늘: 2024년 03월 16일
print(f"시간: {now:%p %I시 %M분}")
# 시간: PM 02시 30분
|
날짜 포맷 코드
| 코드 | 의미 | 예시 |
%Y | 4자리 연도 | 2024 |
%m | 월 (01-12) | 03 |
%d | 일 (01-31) | 16 |
%H | 시 (00-23) | 14 |
%M | 분 (00-59) | 30 |
%S | 초 (00-59) | 45 |
진법 변환 (2진수, 8진수, 16진수)
1
2
3
4
5
6
7
8
9
10
11
12
| number = 255
print(f"10진수: {number}") # 10진수: 255
print(f"16진수: {number:x}") # 16진수: ff
print(f"16진수(대문자): {number:X}") # 16진수(대문자): FF
print(f"2진수: {number:b}") # 2진수: 11111111
print(f"8진수: {number:o}") # 8진수: 377
# 접두사 포함
print(f"16진수: {number:#x}") # 16진수: 0xff
print(f"2진수: {number:#b}") # 2진수: 0b11111111
print(f"8진수: {number:#o}") # 8진수: 0o377
|
중첩 표현식과 조건식
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 조건식 사용
age = 25
status = f"성인" if age >= 18 else "미성년자"
print(f"나이 {age}세: {status}") # 나이 25세: 성인
# 삼항 연산자 활용
score = 85
print(f"{'합격' if score >= 60 else '불합격'}") # 합격
# 리스트 활용 (참고: Day 18에서 리스트 컴프리헨션 학습)
numbers = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25] # 미리 계산된 값
print(f"제곱: {squares}")
# 제곱: [1, 4, 9, 16, 25]
|
딕셔너리와 객체 활용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # 딕셔너리 값 접근
person = {"name": "홍길동", "age": 25, "city": "서울"}
print(f"{person['name']}님은 {person['city']}에 삽니다.")
# 홍길동님은 서울에 삽니다.
# 객체 활용 예시 (참고: Day 31에서 클래스 학습)
# 아래는 참고용 예제입니다
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
student = Student("김철수", 95)
print(f"{student.name}의 점수: {student.score}점")
# 김철수의 점수: 95점
|
특수 문자와 이스케이프
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 중괄호 표시하기 ({{와 }}로 이스케이프)
print(f"Python 딕셔너리는 {{key: value}} 형식입니다.")
# Python 딕셔너리는 {key: value} 형식입니다.
# 백슬래시
path = "C:\\Users\\Documents"
print(f"경로: {path}")
# 경로: C:\Users\Documents
# 작은따옴표/큰따옴표 혼용
name = "홍길동"
print(f'{name}이 말했다: "안녕하세요!"')
# 홍길동이 말했다: "안녕하세요!"
|
🎯 학습 목표 4: 다른 포맷팅 방법과 비교하기
% 포맷팅 (구식, Python 2 시절)
1
2
3
4
5
6
7
8
| name = "홍길동"
age = 25
# % 포맷팅
message = "%s의 나이는 %d세입니다." % (name, age)
print(message)
# 단점: 타입 지정자를 외워야 함 (%s, %d, %f 등)
|
1
2
3
4
5
6
7
8
9
10
11
12
| name = "홍길동"
age = 25
# .format() 메서드
message = "{}의 나이는 {}세입니다.".format(name, age)
print(message)
# 인덱스 지정 가능
message = "{1}의 나이는 {0}세입니다.".format(age, name)
# 이름 지정 가능
message = "{name}의 나이는 {age}세입니다.".format(name="홍길동", age=25)
|
비교표
| 방법 | 가독성 | 속도 | 간결성 | 추천도 |
+ 연결 | ⭐ | ⭐⭐⭐ | ⭐ | ❌ |
% 포맷팅 | ⭐⭐ | ⭐⭐ | ⭐⭐ | ❌ |
.format() | ⭐⭐⭐ | ⭐⭐ | ⭐⭐ | △ |
| f-string | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ✅ |
f-string을 사용해야 하는 이유
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| name = "홍길동"
age = 25
city = "서울"
# ❌ + 연결: 타입 변환 필요, 읽기 어려움
msg1 = name + "(" + str(age) + "세)는 " + city + "에 삽니다."
# ❌ % 포맷팅: 타입 지정자 외워야 함
msg2 = "%s(%d세)는 %s에 삽니다." % (name, age, city)
# △ .format(): 길고 장황함
msg3 = "{}({}세)는 {}에 삽니다.".format(name, age, city)
# ✅ f-string: 직관적이고 간결함!
msg4 = f"{name}({age}세)는 {city}에 삽니다."
|
💻 실습 예제
예제 1: 성적표
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| name = "홍길동"
korean = 85
english = 92
math = 78
average = (korean + english + math) / 3
print("=" * 30)
print(f"{'과목':<10}{'점수':>10}")
print("-" * 30)
print(f"{'국어':<10}{korean:>10}")
print(f"{'영어':<10}{english:>10}")
print(f"{'수학':<10}{math:>10}")
print("-" * 30)
print(f"{'평균':<10}{average:>10.2f}")
print("=" * 30)
|
예제 2: 영수증
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| items = [
{"name": "사과", "price": 1000, "qty": 3},
{"name": "바나나", "price": 1500, "qty": 2},
{"name": "우유", "price": 2500, "qty": 1}
]
print("\n===== 영수증 =====")
grand_total = 0
for item in items:
name = item["name"]
price = item["price"]
qty = item["qty"]
total = price * qty
grand_total += total
print(f"{name:<8} {price:>6,}원 x {qty} = {total:>8,}원")
print("=" * 30)
print(f"{'총액:':<20}{grand_total:>8,}원")
|
예제 3: 진행률 표시
1
2
3
4
5
6
7
8
9
10
| total = 100
current = 37
percent = (current / total) * 100
bar_length = 20
filled = int((current / total) * bar_length)
bar = "█" * filled + "░" * (bar_length - filled)
print(f"진행률: [{bar}] {percent:.1f}%")
# 진행률: [███████░░░░░░░░░░░░░] 37.0%
|
💡 실전 팁 & 주의사항
Tip 1: Python 버전 확인
1
2
3
4
5
6
7
8
9
| # f-string은 Python 3.6+ 에서만 사용 가능
import sys
print(f"Python 버전: {sys.version_info.major}.{sys.version_info.minor}")
# Python 3.5 이하에서는 .format() 사용
if sys.version_info < (3, 6):
message = "{}의 나이는 {}세".format(name, age)
else:
message = f"{name}의 나이는 {age}세"
|
Tip 2: 디버깅에 활용하기 (Python 3.8+)
1
2
3
4
5
6
7
8
9
10
11
12
| # = 기호로 변수 이름과 값을 동시에 출력
name = "홍길동"
age = 25
score = 95.5
print(f"{name=}") # name='홍길동'
print(f"{age=}") # age=25
print(f"{score=:.1f}") # score=95.5
# 디버깅에 매우 유용!
result = 100 + 200
print(f"{result=}") # result=300
|
Tip 3: 여러 줄 f-string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| name = "홍길동"
age = 25
city = "서울"
# 여러 줄로 나누기
message = (
f"{name}님은 {city}에 사는 "
f"{age}세입니다."
)
print(message)
# 또는 삼중 따옴표 사용
info = f"""
이름: {name}
나이: {age}세
도시: {city}
"""
print(info)
|
Tip 4: 표현식 길이 제한
1
2
3
4
5
6
7
8
| # ❌ 너무 복잡한 표현식은 피하기 (가독성 저하)
result = f"{sum([x**2 for x in range(10) if x % 2 == 0]) / len([x for x in range(10) if x % 2 == 0])}"
# ✅ 변수로 분리하기 (가독성 향상)
# 아래는 리스트 컴프리헨션 예시 (Day 18에서 학습)
even_squares = [0, 4, 16, 36, 64] # 0, 2, 4, 6, 8의 제곱
average = sum(even_squares) / len(even_squares)
result = f"평균: {average:.2f}"
|
Tip 5: 중괄호 이스케이프 실수
1
2
3
4
5
6
7
8
9
| # ❌ 잘못된 방법
# print(f"Set: {1, 2, 3}") # SyntaxError!
# ✅ 올바른 방법 1: 변수 사용
my_set = {1, 2, 3}
print(f"Set: {my_set}")
# ✅ 올바른 방법 2: 중괄호 이스케이프
print(f"Set: {{1, 2, 3}}")
|
Tip 6: None 값 처리
1
2
3
4
5
6
7
8
9
| name = None
age = None
# None은 "None"으로 출력됨
print(f"이름: {name}, 나이: {age}") # 이름: None, 나이: None
# 기본값 지정
print(f"이름: {name or '미입력'}, 나이: {age or '미입력'}")
# 이름: 미입력, 나이: 미입력
|
🧪 연습 문제
문제 1: 학생 성적 관리 시스템
과제: 학생들의 성적 정보를 아름답게 포맷팅하여 성적표를 출력하는 프로그램을 작성하세요.
초기 데이터:
1
2
3
4
5
6
| students = [
{"name": "홍길동", "korean": 85, "english": 92, "math": 78},
{"name": "김철수", "korean": 90, "english": 88, "math": 95},
{"name": "이영희", "korean": 78, "english": 85, "math": 90},
{"name": "박민수", "korean": 95, "english": 90, "math": 88}
]
|
요구사항:
- 헤더 행을 출력하기 (이름, 국어, 영어, 수학, 평균, 학점)
- 각 학생별로 다음 정보를 정렬하여 표 형식으로 출력하기:
- 이름: 왼쪽 정렬 8칸
- 각 과목 점수: 오른쪽 정렬 6칸
- 평균: 오른쪽 정렬 6칸, 소수점 첫째 자리까지
- 학점: 가운데 정렬 4칸
- 학점 기준: 90 이상 A, 80 이상 B, 70 이상 C, 나머지 D
- 구분선으로 표를 깔끔하게 구분하기
- 전체 학생의 평균 점수도 계산하여 하단에 출력하기
💡 힌트
- 왼쪽 정렬:
{변수:<너비} - 오른쪽 정렬:
{변수:>너비} - 가운데 정렬:
{변수:^너비} - 소수점 포맷:
{변수:.1f} - 평균 = (국어 + 영어 + 수학) / 3
if-elif-else로 학점 결정
✅ 정답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| students = [
{"name": "홍길동", "korean": 85, "english": 92, "math": 78},
{"name": "김철수", "korean": 90, "english": 88, "math": 95},
{"name": "이영희", "korean": 78, "english": 85, "math": 90},
{"name": "박민수", "korean": 95, "english": 90, "math": 88}
]
print("=" * 56)
print(f"{'이름':<8}{'국어':>6}{'영어':>6}{'수학':>6}{'평균':>6}{'학점':^6}")
print("=" * 56)
total_avg = 0
for student in students:
name = student["name"]
korean = student["korean"]
english = student["english"]
math = student["math"]
# 평균 계산
average = (korean + english + math) / 3
total_avg += average
# 학점 결정
if average >= 90:
grade = "A"
elif average >= 80:
grade = "B"
elif average >= 70:
grade = "C"
else:
grade = "D"
# 성적표 출력
print(f"{name:<8}{korean:>6}{english:>6}{math:>6}{average:>6.1f}{grade:^6}")
print("=" * 56)
class_average = total_avg / len(students)
print(f"{'전체 평균':>32}{class_average:>6.1f}")
print("=" * 56)
|
출력:
1
2
3
4
5
6
7
8
9
10
| ========================================================
이름 국어 영어 수학 평균 학점
========================================================
홍길동 85 92 78 85.0 B
김철수 90 88 95 91.0 A
이영희 78 85 90 84.3 B
박민수 95 90 88 91.0 A
========================================================
전체 평균 87.8
========================================================
|
문제 2: 쇼핑몰 영수증 출력 시스템
과제: 여러 상품의 가격, 수량, 할인율을 계산하여 쇼핑몰 영수증을 출력하는 프로그램을 작성하세요.
초기 데이터:
1
2
3
4
5
6
| products = [
{"name": "노트북", "price": 1500000, "quantity": 1, "discount": 0.10},
{"name": "마우스", "price": 35000, "quantity": 2, "discount": 0.05},
{"name": "키보드", "price": 89000, "quantity": 1, "discount": 0.15},
{"name": "모니터", "price": 450000, "quantity": 2, "discount": 0.20}
]
|
요구사항:
- 영수증 헤더 출력 (상품명, 단가, 수량, 할인율, 금액)
- 각 상품별로 다음 정보 출력:
- 상품명: 왼쪽 정렬 10칸
- 단가: 오른쪽 정렬, 천 단위 쉼표
- 수량: 오른쪽 정렬 4칸
- 할인율: 퍼센트 형식 (소수점 없이)
- 금액: 오른쪽 정렬, 천 단위 쉼표 (할인 적용 후)
- 하단에 총 상품 개수, 총 할인 금액, 최종 결제 금액 출력
- 금액 계산: 단가 × 수량 × (1 - 할인율)
💡 힌트
- 천 단위 쉼표:
{변수:,} - 퍼센트 포맷:
{변수:.0%} (소수점 없이) - 소수점 없는 정수:
{변수:.0f} - 금액 계산:
단가 × 수량 × (1 - 할인율) - 할인 금액 = 정가 - 할인가
✅ 정답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| products = [
{"name": "노트북", "price": 1500000, "quantity": 1, "discount": 0.10},
{"name": "마우스", "price": 35000, "quantity": 2, "discount": 0.05},
{"name": "키보드", "price": 89000, "quantity": 1, "discount": 0.15},
{"name": "모니터", "price": 450000, "quantity": 2, "discount": 0.20}
]
print("=" * 70)
print(f"{'':^70}")
print(f"{'🛒 쇼핑몰 영수증':^70}")
print(f"{'':^70}")
print("=" * 70)
print(f"{'상품명':<10}{'단가':>12}{'수량':>6}{'할인율':>8}{'금액':>15}")
print("-" * 70)
total_original = 0
total_discounted = 0
total_quantity = 0
for product in products:
name = product["name"]
price = product["price"]
quantity = product["quantity"]
discount = product["discount"]
# 금액 계산
original_amount = price * quantity
discounted_amount = original_amount * (1 - discount)
total_original += original_amount
total_discounted += discounted_amount
total_quantity += quantity
# 상품 정보 출력
print(f"{name:<10}{price:>12,}원{quantity:>5}개{discount:>7.0%}{discounted_amount:>14,.0f}원")
print("=" * 70)
# 할인 금액 계산
total_discount = total_original - total_discounted
# 결제 정보 출력
print(f"{'총 상품 개수:':<20}{total_quantity:>10}개")
print(f"{'총 금액:':<20}{total_original:>13,}원")
print(f"{'총 할인 금액:':<20}{total_discount:>13,.0f}원")
print("-" * 70)
print(f"{'최종 결제 금액:':<20}{total_discounted:>13,.0f}원")
print("=" * 70)
print(f"{'감사합니다! 😊':^70}")
print("=" * 70)
|
출력:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| ======================================================================
🛒 쇼핑몰 영수증
======================================================================
상품명 단가 수량 할인율 금액
----------------------------------------------------------------------
노트북 1,500,000원 1개 10% 1,350,000원
마우스 35,000원 2개 5% 66,500원
키보드 89,000원 1개 15% 75,650원
모니터 450,000원 2개 20% 720,000원
======================================================================
총 상품 개수: 6개
총 금액: 2,163,000원
총 할인 금액: 250,850원
----------------------------------------------------------------------
최종 결제 금액: 1,912,150원
======================================================================
감사합니다! 😊
======================================================================
|
🎯 연습 문제 핵심 포인트
문제 1에서 배운 것:
- 정렬 포맷 조합:
< (왼쪽), > (오른쪽), ^ (가운데) - 숫자 포맷: 소수점 자리 제어 (
.1f) - 표 형식 출력: 구분선과 헤더로 가독성 향상
- 조건문으로 학점 판정 로직 구현
- 집계 데이터 (전체 평균) 계산 및 출력
문제 2에서 배운 것:
- 복합 포맷팅: 천 단위 쉼표(
,) + 소수점(.0f) 조합 - 퍼센트 포맷:
.0%로 할인율 표현 - 가운데 정렬로 영수증 스타일 헤더 만들기
- 실전 쇼핑몰 영수증 레이아웃 구현
- 다중 변수 집계 (총 금액, 할인 금액, 수량)
📝 오늘 배운 내용 정리
- f-string 기본:
f"{변수}"로 간단하게 변수 삽입, Python 3.6+ - 숫자 포맷팅:
{num:.2f} (소수점), {num:,} (천 단위), {num:.1%} (퍼센트) - 정렬과 패딩:
{text:<10} (왼쪽), {text:>10} (오른쪽), {text:^10} (가운데) - 고급 기능: 날짜 포맷팅, 진법 변환, 조건식, 딕셔너리/객체 접근
- 다른 방법 비교: f-string이 가장 직관적이고 빠름 (% 포맷팅, .format()보다 우수)
- 디버깅:
{변수=} (Python 3.8+)로 변수 이름과 값 동시 출력
🔗 관련 자료
📚 이전 학습
Day 15: 자료형 변환 (타입 캐스팅) ⭐
어제는 타입 캐스팅으로 자료형을 변환하는 방법을 배웠습니다!
📚 다음 학습
Day 17: 문자열 메서드 활용 ⭐⭐
내일은 문자열을 조작하는 다양한 메서드를 배웁니다!
“늦었다고 생각할 때가 가장 빠른 시기입니다!” 🚀
| Day 16/100 | Phase 2: 자료형 마스터하기 | #100DaysOfPython |