이 페이지의 목차
출력의 형식을 정하다
코드 예제: Python · C · 예상 50분
학습 목표
- 출력 기능의 역할을 설명한다.
- 형식을 지정하여 원하는 모양으로 값을 출력한다.
관련 성취기준
- 프그02-02
입력과 출력의 기능을 이해하고, 형식을 지정하여 데이터를 입력하고 출력할 수 있다.
생각 열기 — 숫자가 줄줄이 나오면
성적을 계산해 이렇게 찍었다.
국어 88
영어 92.5
수학 75
평균 85.16666666666667
값은 다 맞다. 그런데 읽기가 불편하다. 숫자가 시작하는 자리가 들쭉날쭉하고, 평균은 소수점이 열네 자리나 나온다.
출력 — 프로그램이 사람에게 말하는 유일한 창구
프로그램이 아무리 옳게 계산해도 화면에 나오지 않으면 사용자는 알 수 없다. 1단원 6차시에서 알고리즘의 조건으로 “출력이 하나 이상 나온다”를 든 것이 이 때문이다.
출력을 다룰 때 정하는 것은 셋이다.
- 무엇을
어떤 값을 보여 줄까
계산한 값 전부가 아니라 사용자가 필요한 것만. 중간 계산값은 감춘다.
- 어떻게
자리와 자릿수
자리를 맞추면 표처럼 읽힌다. 소수는 몇 자리까지 보일지 정한다.
- 어디에
한 줄인가 이어 붙이나
줄을 바꿀지 말지 정한다. 표를 만들 때는 줄바꿈을 미루기도 한다.
형식 지정 — 자리와 자릿수를 정한다
형식 지정(formatting) — 값을 어떤 모양으로 문자열에 넣을지 정하는 일. 폭과 소수 자릿수, 정렬을 정한다은 값을 문자열에 끼워 넣을 때 모양을 정하는 일이다.
과목 = ["국어", "영어", "수학"]
점수 = [88, 92.5, 75]
for i in range(3):
print(f"{과목[i]} {점수[i]:>6.1f}")
print(f"평균 {sum(점수) / 3:>6.1f}")국어 88.0 영어 92.5 수학 75.0 평균 85.2
#include <stdio.h>
int main(void)
{
const char *subject[] = {"국어", "영어", "수학"};
double score[] = {88.0, 92.5, 75.0};
double sum = 0;
for (int i = 0; i < 3; i++) {
printf("%s %6.1f\n", subject[i], score[i]);
sum += score[i];
}
printf("평균 %6.1f\n", sum / 3);
return 0;
}국어 88.0 영어 92.5 수학 75.0 평균 85.2
두 언어의 출력이 글자 하나까지 같다. 형식을 정해 두면 언어가 달라도 같은 모양이 나온다는 것을 보여 주는 예다.
:>6.1f 를 뜯어 보면
{점수 : > 6 .1 f}
│ │ │ │ │
│ │ │ │ └─ 실수로 (float)
│ │ │ └────── 소수점 아래 한 자리
│ │ └──────────── 전체 여섯 칸을 차지하게
│ └───────────────── 오른쪽으로 붙여 (right)
└──────────────────── 여기서부터 형식 지정
C의 %6.1f 도 같은 뜻이다. 숫자는 오른쪽 정렬이 기본이라 > 에 해당하는 표시가 없다.
| 하려는 일 | Python | C |
|---|---|---|
| 정수 그대로 | {n} | %d |
| 실수 소수 한 자리 | {x:.1f} | %.1f |
| 여섯 칸에 오른쪽 정렬 | {x:>6} | %6d / %6.1f |
| 여섯 칸에 왼쪽 정렬 | {x:<6} | %-6d |
| 천 단위 쉼표 | {n:,} | 따로 없다. 직접 만들어야 한다 |
| 문자열 그대로 | {s} | %s |
한글은 자리 맞춤이 언어마다 다르다
3차시에서 예고한 함정이 여기서 나온다. 위 예제는 과목 이름에 폭을 지정하지 않았다. 일부러 그렇게 했다.
- Python의
f"{과목:<8}"은 글자 수로 여덟 칸을 센다.국어는 2칸으로 세고 6칸을 채운다. - C의
%-8s는 바이트 수로 여덟 칸을 센다.국어는 6바이트로 세고 2칸만 채운다.
같은 8 을 적어도 결과가 다르다. 그래서 이 교과서의 예제는 한글에는 폭을 주지 않고 숫자에만 준다.
줄바꿈을 다루는 법
print 는 끝에 줄바꿈을 자동으로 넣는다. 표를 만들 때는 그것을 막아야 한다.
| 하려는 일 | Python | C |
|---|---|---|
| 찍고 줄바꿈 | print(x) | printf("%d\\n", x) |
| 줄바꿈 없이 이어 찍기 | print(x, end="") | printf("%d", x) — 원래 안 넣는다 |
| 빈 줄 하나 | print() | printf("\\n") |
| 값 사이에 넣을 것 정하기 | print(a, b, sep=", ") | 형식 문자열에 직접 적는다 |
C는 줄바꿈을 자동으로 넣지 않는다. \n 을 빠뜨리면 출력이 죄다 한 줄에 붙어 나온다. 반대로 Python은 넣는 것이 기본이라 막을 때 end="" 를 적는다. 11차시에서 별 찍기를 할 때 이 차이를 실제로 쓴다.
활동
표 모양으로 정렬된 성적표 출력하기
약 25분1단계 — 폭을 바꿔 본다 (10분)
실행기의 [고치기]로 숫자 부분의 형식만 바꿔 보고 결과를 적는다.
| 형식 | 결과 (공백을 · 로 표시해 적기) |
|---|---|
{점수:>6.1f} |
|
{점수:>10.1f} |
|
{점수:<6.1f} |
|
{점수:>6.0f} |
|
{점수:>6.3f} |
|
{점수:6d} (정수로) |
- 폭을 값보다 작게 주면 어떻게 되는가? (
{점수:>2.1f}로 해 보자) .0f로 하면 소수 첫째 자리는 버려지는가, 반올림되는가?92.5로 확인한다.
2단계 — 머리글을 붙인다 (5분)
표에 머리글과 구분선을 넣어 아래처럼 만들어 보자.
과목 점수
------------
국어 88.0- 구분선은 어떻게 만드는 것이 편한가? (Python에서
"-" * 12를 해 보자)
3단계 — 한글 자리 맞춤을 겪어 본다 (10분)
과목 이름을 길이가 다른 것으로 바꾼다 — ["국어", "사회문화", "수학"].
- 폭을 주지 않은 지금 코드에서 숫자 자리가 어긋나는가?
- Python에서
f"{과목[i]:<8}"처럼 폭을 주면 맞아지는가? - 같은 폭을 C의
%-8s로 주면 어떻게 되는가? 두 결과를 나란히 적어 견줘 본다.
Python :<8 |
C %-8s |
|
|---|---|---|
| 국어 뒤 공백 칸 수 | ||
| 사회문화 뒤 공백 칸 수 | ||
| 숫자가 한 줄로 맞았나 |
왜 다른지 한 문장으로 적는다.
개념 확인 문제
보기를 누르면 바로 채점된다. 틀려도 해설을 읽으면 된다.
Python의 f「{x:>6.1f}」 에서 6 이 뜻하는 것은?프그02-02
표에서 숫자를 오른쪽 정렬하는 까닭으로 가장 알맞은 것은?프그02-02
같은 폭 8 을 주었는데 Python과 C의 결과가 다른 까닭은?프그02-02
C에서 printf(「%d」, x) 를 여러 번 부르면 출력이 한 줄에 붙어 나온다. 그 까닭은?프그02-02
설계 문서에 출력 형식을 띄어쓰기까지 적어 두는 실질적인 이유는?프그02-02
더 알아보기
심화반올림은 생각보다 까다롭다
{92.45:.1f} 이 92.5 가 될지 92.4 가 될지는 짐작하기 어렵다. 2차시에서 다룬 대로 컴퓨터가 실수를 정확히 담지 못하기 때문이다. 92.45 가 실제로는 92.4499… 로 담겨 있으면 내림이 된다. 성적처럼 민감한 값을 다룰 때는 어떻게 반올림할지 요구 사항에 못 박고(3단원 2차시), 경계값으로 테스트해야 한다(3단원 7차시). 정확한 반올림이 필요하면 실수 대신 정수로 계산하는 방법도 있다 — 소수 첫째 자리까지 필요하면 값을 10배 해서 정수로 다루는 식이다.
실무형식 문자열이 세 세대에 걸쳐 바뀌었다
Python에서 문자열에 값을 끼워 넣는 방법은 여러 가지가 있다. 오래된 "%d" % n 방식, 그다음 "{}".format(n) 방식, 그리고 지금 주로 쓰는 f"{n}" 방식이다. 세 방식이 다 남아 있어 남의 코드를 읽을 때 섞여 나온다. 새로 쓸 때는 f 방식을 쓰는 것이 읽기 좋다 — 값이 들어갈 자리에 이름이 그대로 보이기 때문이다. C의 printf 는 오래됐지만 형식 표기가 거의 그대로 남아, Python의 % 방식이나 다른 언어에도 비슷하게 쓰인다. 하나를 익히면 여러 언어에서 통한다.
심화화면에 바로 안 나올 때가 있다
C에서 printf 로 찍었는데 화면에 바로 안 보이는 일이 있다. 출력을 한 글자씩 내보내면 느려서, 어느 정도 모아 두었다가 한꺼번에 내보내기 때문이다. 이것을 버퍼라 한다. 줄바꿈을 만나거나 버퍼가 차면 실제로 나간다. 그래서 프로그램이 중간에 비정상 종료하면 찍었다고 생각한 출력이 안 나올 수 있다. 디버깅할 때 이것 때문에 헷갈리는 일이 있으니, 마지막 출력이 안 보인다고 그 앞이 실행되지 않았다고 단정하지 않는 편이 좋다.
이어지는 학습
이 차시를 이해하려면 다음을 먼저 알아야 한다.
- 2차시의 자료형 — 프로그래밍 프그02-01
교과서에서 찾기
| 교과서 | 해당 위치 | 쪽수 |
|---|---|---|
| 성림출판(Python) | 프로그래밍의 기초 › 02 입력과 출력 | 104쪽 |
| 씨마스커뮤니케이션(Python) | 프로그래밍 기초 › 1 입력과 출력 | 72쪽 |
| 삼양미디어(Python) | 프로그래밍의 기초 › 01 데이터 입출력 (프그02-01과 통합) | 42쪽 |
| 삼양미디어(C) | 프로그래밍의 기초 › 01 데이터 입출력 (프그02-01과 통합) | 42쪽 |
| 씨마스(C) | C 프로그래밍의 기초 › 2 입출력 함수 | 72쪽 |
| 웅보출판사(C) | 프로그래밍의 기초 › Chapter 02 입출력 함수 | 85쪽 |