포스트

[Python 100일 챌린지] Day 16 - 문자열 포맷팅 (f-string)

[Python 100일 챌린지] Day 16 - 문자열 포맷팅 (f-string)

“이름: 홍길동, 나이: 25세” 같은 문자열을 만들 때마다 +str()로 고생하셨나요? f-string 하나면 모든 문제가 해결됩니다! Python 3.6부터 추가된 가장 강력하고 직관적인 문자열 포맷팅 방법을 배워봅시다. 한 번 배우면 다시는 복잡한 문자열 연결로 돌아가지 않을 겁니다! (25분 완독 ⭐⭐)

🎯 오늘의 학습 목표

📚 사전 지식


🎯 학습 목표 1: f-string이 무엇인지 이해하기

f-string이란?

f-string = Formatted String Literal의 약자로, 문자열 안에 변수나 표현식을 쉽게 삽입하는 방법 (Python 3.6+)

문자열 앞에 fF를 붙이고, 중괄호 {}로 변수나 표현식을 감싸면 자동으로 값이 삽입됩니다.

기존 방법의 문제점

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 등)

.format() 메서드 (Python 3.0+)

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}
]

요구사항:

  1. 헤더 행을 출력하기 (이름, 국어, 영어, 수학, 평균, 학점)
  2. 각 학생별로 다음 정보를 정렬하여 표 형식으로 출력하기:
    • 이름: 왼쪽 정렬 8칸
    • 각 과목 점수: 오른쪽 정렬 6칸
    • 평균: 오른쪽 정렬 6칸, 소수점 첫째 자리까지
    • 학점: 가운데 정렬 4칸
  3. 학점 기준: 90 이상 A, 80 이상 B, 70 이상 C, 나머지 D
  4. 구분선으로 표를 깔끔하게 구분하기
  5. 전체 학생의 평균 점수도 계산하여 하단에 출력하기
💡 힌트
  • 왼쪽 정렬: {변수:<너비}
  • 오른쪽 정렬: {변수:>너비}
  • 가운데 정렬: {변수:^너비}
  • 소수점 포맷: {변수:.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}
]

요구사항:

  1. 영수증 헤더 출력 (상품명, 단가, 수량, 할인율, 금액)
  2. 각 상품별로 다음 정보 출력:
    • 상품명: 왼쪽 정렬 10칸
    • 단가: 오른쪽 정렬, 천 단위 쉼표
    • 수량: 오른쪽 정렬 4칸
    • 할인율: 퍼센트 형식 (소수점 없이)
    • 금액: 오른쪽 정렬, 천 단위 쉼표 (할인 적용 후)
  3. 하단에 총 상품 개수, 총 할인 금액, 최종 결제 금액 출력
  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%로 할인율 표현
  • 가운데 정렬로 영수증 스타일 헤더 만들기
  • 실전 쇼핑몰 영수증 레이아웃 구현
  • 다중 변수 집계 (총 금액, 할인 금액, 수량)

📝 오늘 배운 내용 정리

  1. f-string 기본: f"{변수}"로 간단하게 변수 삽입, Python 3.6+
  2. 숫자 포맷팅: {num:.2f} (소수점), {num:,} (천 단위), {num:.1%} (퍼센트)
  3. 정렬과 패딩: {text:<10} (왼쪽), {text:>10} (오른쪽), {text:^10} (가운데)
  4. 고급 기능: 날짜 포맷팅, 진법 변환, 조건식, 딕셔너리/객체 접근
  5. 다른 방법 비교: f-string이 가장 직관적이고 빠름 (% 포맷팅, .format()보다 우수)
  6. 디버깅: {변수=} (Python 3.8+)로 변수 이름과 값 동시 출력

🔗 관련 자료


📚 이전 학습

Day 15: 자료형 변환 (타입 캐스팅)

어제는 타입 캐스팅으로 자료형을 변환하는 방법을 배웠습니다!

📚 다음 학습

Day 17: 문자열 메서드 활용 ⭐⭐

내일은 문자열을 조작하는 다양한 메서드를 배웁니다!


“늦었다고 생각할 때가 가장 빠른 시기입니다!” 🚀

Day 16/100 Phase 2: 자료형 마스터하기 #100DaysOfPython
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.