기초시험의 주교재는 오라이리 재팬의 『Python튜토리얼(Pythonチュートリアル)』로, 공식 페이지에는 2021년 9월 1일부터 제4판에 대응한다고 나와 있다. 출제 범위도 이 책의 장 번호와 장 이름으로 공개되므로 대책은 이 책의 내용을 장별 비중에 맞춰 챙기는 형태가 된다. 기주쓰효론샤 『Python실천레시피』는 실천시험, 쇼에이샤 『Python으로 배우는 새로운 데이터분석의교과서』는 데이터분석시험, 임프레스 『Python데이터분석 실천핸드북』은 데이터분석실천시험의 주교재이며, 모두 같은 협회가 실시하는 다른 시험의 교재이다. 교재를 혼동하면 범위 밖을 계속 공부하게 되므로 맨 처음에 확인해 두어야 한다.
문제 2 | 가장 많은 장
기초시험의 출제 범위에서 주교재 중 가장 많은 문제가 나오는 장은 어느 것인가?
5장 '자료 구조'
4장 '제어 구조 도구'
3장 '가벼운 입문'
8장 '오류와 예외'
정답B. 4장 '제어 구조 도구'
가장 많은 것은 4장 '제어 구조 도구'로, 40문제 중 9문제가 배정되어 있다. 다음으로 5장 '자료 구조'가 7문제, 3장 '가벼운 입문'이 6문제로 이어지며, 8장 '오류와 예외'는 4문제이다. 3장과 4장과 5장만으로 22문제가 되어 전체의 절반을 넘는다. 따라서 학습 시간도 이 세 장에 두껍게 배분하는 것이 합리적이며, 특히 for문과 함수 정의를 다루는 4장을 뒤로 미루면 돌이키기 어렵다.
문제 3 | 장별 배분
기초시험의 출제 범위에서 4장 '제어 구조 도구'가 차지하는 비율은 어느 것인가?
17.5%
10.0%
22.5%
15.0%
정답C. 22.5%
4장 '제어 구조 도구'는 40문제 중 9문제로 비율로 하면 22.5퍼센트이다. 장별로는 최대이며, 다음이 5장 '자료 구조'의 7문제로 17.5퍼센트이다. 15.0퍼센트는 3장 '가벼운 입문'의 6문제에 해당하고, 10.0퍼센트는 8장 '오류와 예외' 및 10장 '표준 라이브러리 둘러보기'의 4문제에 해당하는 비율이다. 이 배분은 운영상의 수치가 아니라 출제 범위 그 자체로 공개되어 있으므로 학습 계획의 근거로 쓸 수 있다.
문제 4 | 13장의 배분
기초시험의 출제 범위에서 13장 '다음은 무엇을?'에 배정되어 있는 문제 수는 어느 것인가?
0문제
1문제
4문제
2문제
정답A. 0문제
13장 '다음은 무엇을?'은 0문제로, 출제 범위 중 유일하게 전혀 출제되지 않는 장이다. 학습의 다음 단계를 안내하는 내용이므로 문법을 묻는 시험으로서는 대상에서 제외되어 있다. 1문제가 배정된 것은 1장·2장·7장·11장·12장·14장, 2문제는 6장과 9장, 4문제는 8장 '오류와 예외'와 10장 '표준 라이브러리 둘러보기'이다. 13장을 제외하면 모두 1문제 이상 있으므로 배분이 적은 장도 용어를 훑어보는 정도의 대비는 해 두어야 한다.
문제 5 | print의 sep
다음 프로그램을 실행했을 때 화면에 출력되는 문자열은 어느 것인가?
print('Python', 3, 'exam', sep='/')
Python3exam
Python 3 exam
Python/3/exam/
Python/3/exam
정답D. Python/3/exam
print()는 받은 인수를 키워드 인수 sep로 이어서 나열한다. sep의 기본값은 반각 공백 1개이므로 지정하지 않으면 Python 3 exam이 되지만, 여기서는 sep='/'를 지정했으므로 슬래시로 이어져 Python/3/exam이 된다. Python3exam은 sep을 빈 문자열로 했을 때의 출력이다. 끝에도 구분자가 붙는 Python/3/exam/을 고르는 것은 sep이 요소 뒤마다 붙는다고 생각한 경우인데, 실제로는 인수와 인수 사이에만 들어간다. 끝에 붙는 것은 end 쪽이다.
문제 6 | print의 end
다음 세 줄을 위에서부터 순서대로 실행했을 때 화면에 나오는 것은 어느 것인가?
print('A', end='')print('B', end='')print('C')
AB 와 C 가 두 줄에 출력된다
ABC 로 한 줄만 출력된다
A B C 로 한 줄만 출력된다
A, B, C 가 세 줄에 출력된다
정답B. ABC 로 한 줄만 출력된다
print()는 출력의 끝에 키워드 인수 end를 붙인다. 기본값은 줄바꿈 문자이므로 지정하지 않으면 print()를 호출할 때마다 줄이 바뀐다. 여기서는 처음 두 개에서 end=''로 줄바꿈을 멈추었으므로 A와 B가 이어서 출력되고, 마지막 print()가 기본값인 줄바꿈을 붙이므로 ABC로 한 줄만 출력된다. A B C처럼 공백이 들어가는 것은 한 번의 print()에 세 개의 인수를 넘긴 경우, 세 줄로 나뉘는 것은 end를 전혀 지정하지 않은 경우, 두 줄이 되는 것은 end=''를 하나만 뺀 경우이다.
문제 7 | 언팩 출력
리스트를 펼쳐서 표시하는 다음 프로그램의 출력은 어느 것인가?
nums = [10, 20, 30]print(*nums, sep=', ')
10, 20, 30 으로 출력된다
102030 으로 출력된다
[10, 20, 30] 으로 출력된다
10 20 30 으로 출력된다
정답A. 10, 20, 30 으로 출력된다
별표를 붙인 print(*nums)는 리스트의 각 요소를 개별 인수로 print()에 전달한다. 따라서 세 개의 인수가 sep로 이어져, sep=', '이므로 10, 20, 30 이 된다. 별표를 붙이지 않고 print(nums)라고 쓰면 리스트가 하나의 인수로 전달되어 대괄호가 붙은 [10, 20, 30] 이 그대로 나온다. sep을 지정하지 않으면 기본값인 반각 공백으로 10 20 30 이 되고, sep=''이면 102030 처럼 붙어서 출력된다.
문제 8 | 주석 기호
Python의 주석에 대한 설명으로 옳은 것은 어느 것인가?
/* 와 */ 로 둘러싸인 범위가 주석으로 무시된다
# 부터 줄 끝까지가 주석으로 무시된다
-- 부터 줄 끝까지가 주석으로 무시된다
// 부터 줄 끝까지가 주석으로 무시된다
정답B. # 부터 줄 끝까지가 주석으로 무시된다
Python의 주석은 샵 기호(#)로 쓰며, 거기서부터 줄 끝까지가 무시된다. 줄 맨 앞에 두면 그 줄 전체가, 도중에 두면 그 이후가 대상이 된다. 여러 줄을 한꺼번에 묶는 전용 구문은 없으므로 줄마다 샵을 둔다. 삼중 인용부호로 둘러싸는 표기법을 블록 주석 대신 쓰는 경우도 있지만 그것은 문법상 문자열 리터럴이며, 함수나 클래스의 맨 앞에 두면 독스트링(docstring)으로서 실행 시에 유지된다. 이중 슬래시는 Python에서는 몫 연산자, 슬래시와 별표 조합이나 하이픈 두 개는 다른 언어의 주석 표기법이다.
문제 9 | 들여쓰기
다음 프로그램을 파일에 저장해 실행하면 어떻게 되는가?
if True: print('one') print('two')
two 만 출력되고 처리가 끝난다
one 만 출력되고 처리가 끝난다
one 과 two 가 이 순서로 출력된다
IndentationError 가 발생해 멈춘다
정답D. IndentationError 가 발생해 멈춘다
Python은 들여쓰기의 깊이로 블록을 나타내므로 같은 블록에 속한 문장은 들여쓰기 폭을 맞춰야 한다. 3번째 줄만 깊어져 있는데다 바로 앞 줄이 새로운 블록을 여는 줄(콜론으로 끝나는 줄)이 아니므로 IndentationError: unexpected indent 가 된다. 이는 실행 전 구문 분석 단계에서 검출되므로 2번째 줄의 print도 실행되지 않아 one조차 출력되지 않는다. 들여쓰기가 필요한 곳에서 하지 않으면 expected an indented block, 도중에 폭이 맞지 않게 되면 unindent does not match any outer indentation level 이라는 다른 메시지가 되지만 둘 다 IndentationError 이다.
문제 10 | 문자 코드
Python 3 소스 파일의 문자 인코딩에 대해 옳은 설명은 어느 것인가?
Shift_JIS가 기본값이며 선언하면 바꿀 수 있다
UTF-8이 기본값이며 일본어를 그대로 쓸 수 있다
EUC-JP가 기본값이며 일본어를 그대로 쓸 수 있다
ASCII가 기본값이며 일본어를 포함하려면 선언이 필요하다
정답B. UTF-8이 기본값이며 일본어를 그대로 쓸 수 있다
Python 3의 소스 파일은 기본적으로 UTF-8로 읽히므로 주석에도 문자열 리터럴에도 일본어를 그대로 쓸 수 있다. Python 2에서는 기본값이 ASCII였기 때문에 일본어를 포함할 때는 파일 1번째나 2번째 줄에 coding 선언을 써야 했지만, Python 3에서는 그 선언이 필요 없어졌다. 선언을 쓰는 것은 UTF-8 이외의 문자 코드로 저장한 파일을 읽게 하고 싶을 때뿐이다. 참고로 식별자(변수명이나 함수명)에도 일본어를 쓸 수는 있지만 가독성 면에서 권장되지 않는다.
문제 11 | 나눗셈의 타입
정수끼리의 나눗셈을 다루는 다음 프로그램은 1번째 줄에 값을, 2번째 줄에 타입 이름을 출력한다. 그 조합은 어느 것인가?
print(9 / 3)print(type(9 / 3).__name__)
값이 3.0 이고 타입은 int
값이 3.0 이고 타입은 float
값이 3 이고 타입은 int
값이 3 이고 타입은 float
정답B. 값이 3.0 이고 타입은 float
슬래시 한 개(/)는 참 나눗셈으로 결과는 반드시 float가 된다. 나누어떨어지는 경우도 예외가 아니므로 9 / 3 은 3 이 아니라 3.0 이며 타입도 float이다. 정수끼리의 계산이니까 int가 될 것이라 생각하면 3과 int를 고르게 되지만, int를 원한다면 몫 연산을 써서 9 // 3 이라고 써야 하며 이 경우라면 3과 int가 된다. 3과 float, 3.0과 int처럼 값의 겉모습과 타입이 어긋나는 조합은 이 식에서는 나오지 않는다.
문제 12 | 음수의 몫 연산
몫 연산을 나열한 다음 프로그램의 출력은 어느 것인가?
print(9 // 4)print(-9 // 4)
1번째 줄이 2.0, 2번째 줄이 -3.0
1번째 줄이 2, 2번째 줄이 -3
1번째 줄이 2.25, 2번째 줄이 -2.25
1번째 줄이 2, 2번째 줄이 -2
정답B. 1번째 줄이 2, 2번째 줄이 -3
슬래시 두 개(//)는 몫 연산으로, 몫을 아래쪽, 즉 수직선 상에서 더 작은 쪽으로 내림한다. 9 / 4 는 2.25 이므로 9 // 4 는 2, -9 / 4 는 -2.25 이므로 -9 // 4 는 -2 가 아니라 -3 이 된다. 0에 가까워지는 방향이 아니라는 점이 요점이며, -2를 고르는 것은 C언어처럼 0 방향으로 내림한다고 생각한 경우이다. 2.25와 -2.25는 //가 아니라 /를 썼을 때의 값, 2.0과 -3.0은 피연산자에 float를 섞어 9.0 // 4 로 썼을 때의 값이며, 양변이 int이면 결과도 int가 된다.
문제 13 | divmod
divmod(-11, 3) 이 반환하는 값은 어느 것인가?
(-4, 1)
(-3, -2)
(-4, -2)
(-3, 2)
정답A. (-4, 1)
divmod(a, b) 는 (a // b, a % b) 라는 튜플을 반환한다. Python의 //는 아래 방향으로 내림하므로 -11 // 3 은 -4 가 되고, 나머지의 부호는 오른쪽 변에 맞춰지므로 -11 % 3 은 1 이 된다. 따라서 (-4, 1) 이다. 0 방향으로 내림하는 방식으로 생각하면 몫이 -3, 나머지가 -2 가 되어 (-3, -2) 를 고르게 되지만 Python은 이 방식을 쓰지 않는다. 몫과 나머지는 항상 제수 곱하기 몫 더하기 나머지가 원래 값으로 돌아오는 관계를 유지하므로 3 곱하기 -4 더하기 1 로 -11 이 되어 검산할 수 있다. 이 관계로 확인하면 (-3, 2) 도 (-4, -2) 도 -11 로 돌아오지 않는다.
문제 14 | int의 내림
내림하는 방향을 비교하는 다음 프로그램의 출력은 어느 것인가?
print(int(-2.7))print(-2.7 // 1)
1번째 줄이 -2, 2번째 줄이 -2.0
1번째 줄이 -3, 2번째 줄이 -3.0
1번째 줄이 -2, 2번째 줄이 -3.0
1번째 줄이 -3, 2번째 줄이 -2.0
정답C. 1번째 줄이 -2, 2번째 줄이 -3.0
내장 함수 int() 는 소수부를 버리고 0에 가까워지는 방향으로 반올림하므로 int(-2.7) 은 -3 이 아니라 -2 가 된다. 한편 //는 아래 방향으로 내림하므로 -2.7 // 1 은 -3 쪽이 되고, 피연산자에 float가 포함되어 있으므로 결과도 float인 -3.0 이다. 양수에서는 int(2.7) 도 2.7 // 1 도 둘 다 2 쪽이 되어 차이가 보이지 않지만 음수에서 방향이 갈린다. 둘 다 반올림이 아니므로 -2.7 을 -3 으로 만들고 싶을 때는 round(-2.7) 을 사용한다.
float는 소수를 2진수로 저장하므로 10진으로는 간단한 0.1이나 0.7을 정확하게는 표현할 수 없다. 실제로 0.1 + 0.7 을 표시하면 0.7999999999999999 가 되어 0.8과는 미세하게 다르므로 1번째 줄은 False가 된다. 2번째 줄은 round()로 소수점 이하 2자리로 반올림한 뒤 비교하므로 양변이 0.8이 되어 True이다. 이는 Python 고유의 결함이 아니라 IEEE 754 이진 부동소수점의 성질로, 0.1 + 0.2 가 0.30000000000000004 가 되고 1.1 + 2.2 가 3.3000000000000003 이 되는 것도 같은 이유이다. float의 등가 비교는 피하고, 필요한 자릿수로 반올림한 뒤 비교하거나, 허용 오차와 차이의 절댓값을 비교하거나, 금액처럼 정밀함이 필요한 장면에서는 decimal 모듈을 쓴다.
문제 16 | round의 반올림
반올림한 값을 한 줄에 나열하는 다음 프로그램의 출력은 어느 것인가?
print(round(1.5), round(2.5), round(3.5))
2 2 4
2 3 4
1 3 3
1 2 3
정답A. 2 2 4
Python의 round() 는 가장 가까운 짝수로 반올림하는, 이른바 은행가 반올림을 수행한다. 정확히 절반인 값일 때만 가까운 쪽 짝수로 붙이므로 1.5는 2, 2.5는 2, 3.5는 4가 되어 출력은 2 2 4 이다. 학교에서 배우는 사사오입이라면 2 3 4 가 되지만 Python은 이 방식을 쓰지 않는다. 1 2 3 은 소수점 이하를 단순히 버렸을 때의 값, 1 3 3 은 홀수 쪽으로 붙였을 때의 값으로, 둘 다 실제 동작과는 다르다. 참고로 두 번째 인수를 생략한 round()는 int를 반환하고, round(2.5, 0)처럼 자릿수를 지정하면 float인 2.0이 반환된다.
문제 17 | bool은 int
진리값을 숫자로 다루는 다음 프로그램의 출력은 어느 것인가?
print(True + True)print(isinstance(True, int))
1번째 줄이 True, 2번째 줄이 True
1번째 줄이 2, 2번째 줄이 False
1번째 줄이 2, 2번째 줄이 True
1번째 줄이 True, 2번째 줄이 False
정답C. 1번째 줄이 2, 2번째 줄이 True
bool은 int를 상속한 타입이므로 True는 정수 1, False는 정수 0으로 그대로 수치 연산에 쓸 수 있다. True + True 는 1 더하기 1 로 2가 되고, isinstance(True, int) 는 True를 반환한다. 1번째 줄을 True라고 생각해 버리는 것은 +를 논리합과 혼동한 경우로, Python의 논리합은 or이며 True or True 라면 True가 된다. issubclass(bool, int) 도 True이며, sum([True, False, True]) 가 2가 되는 것도 같은 이유이다. 조건을 만족한 개수를 셀 때 이 성질이 자주 쓰인다.
문제 18 | 정수의 정밀도
Python 3의 int 타입에 대한 설명으로 옳은 것은 어느 것인가?
자릿수의 상한이 없으며 메모리가 허락하는 한 큰 값을 다룰 수 있다
32비트를 넘는 값은 넘쳐서 음수가 되는 경우가 있다
자릿수가 상한을 넘은 시점에 OverflowError 가 발생한다
64비트를 넘으면 자동으로 float로 변환되어 계산된다
정답A. 자릿수의 상한이 없으며 메모리가 허락하는 한 큰 값을 다룰 수 있다
Python 3의 int는 임의 정밀도로 자릿수에 상한이 없다. 3 ** 40 은 12157665459056928801 로 정확히 구해지는데, 이는 부호 있는 64비트 범위를 넘지만 타입은 int인 채로 있다. 2 ** 1000 같은 값도 다룰 수 있으며 자릿수를 len(str(2 ** 1000)) 으로 세면 302자리가 된다. C언어 같은 고정 길이 정수가 아니므로 넘쳐서 음수가 되는 일도, 멋대로 float로 바뀌는 일도 없다. OverflowError는 float가 표현할 수 있는 범위를 넘었을 때 등에 나오는 것으로, int의 자릿수가 늘어난 것만으로는 발생하지 않는다. 다만 자릿수가 늘어날수록 계산 시간과 메모리는 늘어난다.
문제 19 | bytes의 첨자
바이트열을 다루는 다음 프로그램의 2번째 줄과 3번째 줄 출력은 어느 것인가?
b = 'abc'.encode()print(b[0])print(b[0:1])
1번째 줄이 b'a', 2번째 줄이 b'a'
1번째 줄이 97, 2번째 줄이 b'a'
1번째 줄이 97, 2번째 줄이 97
1번째 줄이 a, 2번째 줄이 b'a'
정답B. 1번째 줄이 97, 2번째 줄이 b'a'
bytes에 정수 첨자로 접근하면 그 위치의 바이트 값이 int로 반환된다. 'abc'를 UTF-8로 인코딩한 b'abc'의 첫 바이트는 'a'의 코드 포인트이므로 97이 된다. 한편 슬라이스로 꺼내면 길이 1인 bytes가 반환되므로 b[0:1] 은 b'a' 이다. str이라면 s[0] 도 s[0:1] 도 같은 'a'라는 str이 되므로, 여기가 str과 bytes가 대조적인 부분이다. 표시가 a가 아니라 b'a'가 되는 것은 print()가 bytes를 repr 형태로 내기 때문으로, 문자열로 되돌리고 싶을 때는 b.decode() 를 쓴다.
int() 의 두 번째 인수는 진법이므로 int('1010', 2) 는 문자열을 2진수로 읽어 10 을 반환한다. 1010 그대로 나온다고 생각하는 것은 진법 지정을 못 본 경우이다. bin() 은 접두사 0b가 붙은 문자열을 반환하므로 '0b1010', hex() 는 0x가 붙은 소문자 문자열을 반환하므로 '0xff' 가 된다. 대문자인 0xFF가 되는 일은 없으며, 대문자 표기가 필요할 때는 format(255, 'X') 를 쓴다. ord() 는 문자의 코드 포인트를 반환하며 대문자 A는 65이다. 97은 소문자 a의 코드 포인트이며, 역방향 변환은 chr(65) 라고 쓰면 'A' 로 돌아간다.
문제 21 | 슬라이스
문자열 슬라이스를 다루는 다음 프로그램의 출력은 어느 것인가?
s = 'Pythonic'print(s[2:5])print(s[-3:])
1번째 줄이 tho, 2번째 줄이 nic
1번째 줄이 tho, 2번째 줄이 ic
1번째 줄이 thon, 2번째 줄이 nic
1번째 줄이 yth, 2번째 줄이 nic
정답A. 1번째 줄이 tho, 2번째 줄이 nic
s[2:5] 는 첨자 2의 위치부터 시작해 첨자 5의 바로 앞까지를 꺼낸다. 'Pythonic'의 첨자 2는 t이므로 t, h, o의 3글자로 tho가 된다. 끝 위치는 포함되지 않으므로 thon이 되지는 않는다. 첨자를 1부터 세어 '2번째 글자부터'라고 읽으면 s[1:4] 에 해당하는 yth를 고르게 된다. s[-3:] 은 음수 첨자이므로 끝에서부터 세어, 끝에서 3번째 글자인 n을 시작점으로 마지막까지를 반환하므로 nic이다. -3을 '끝에서 3번째 글자까지'로 잘못 읽으면 s[-2:] 에 해당하는 ic를 고르게 된다. 첨자는 0부터 시작하고 음수 첨자는 끝을 -1로 하여 센다는 두 가지만 짚으면 헷갈리지 않는다.
문제 22 | 범위 밖과 in
두 가지 판정 결과를 표시하는 다음 프로그램의 출력은 어느 것인가?
s = 'Python'print(s[100:200] == '')print('py' in s)
1번째 줄이 True, 2번째 줄이 False
1번째 줄이 True, 2번째 줄이 True
1번째 줄이 False, 2번째 줄이 True
1번째 줄이 False, 2번째 줄이 False
정답A. 1번째 줄이 True, 2번째 줄이 False
슬라이스는 범위가 문자열 길이를 넘어도 예외가 되지 않고 겹치는 부분만 반환한다. 'Python'은 6글자뿐이므로 s[100:200] 은 빈 문자열이 되어 빈 문자열과의 비교는 True가 된다. 단일 첨자 s[100] 이라면 IndexError가 되므로 이 부분이 대조적이다. 2번째 줄의 in 연산자는 부분 문자열의 유무를 조사하는데 대소문자를 구별하므로 소문자 'py'는 'Python'에 포함되지 않아 False가 된다. 'Py'나 'th'라면 True이다.
문제 23 | 문자열은 불변
다음 프로그램을 파일에 써서 실행하면 어떻게 되는가?
s = 'abc's[0] = 'z'print(s)
TypeError 가 발생해 대입할 수 없다
zbc 로 바뀌어 출력된다
IndexError 가 발생해 대입할 수 없다
abc 그대로 바뀌지 않고 출력된다
정답A. TypeError 가 발생해 대입할 수 없다
str은 불변(immutable), 즉 생성 후에 내용을 바꿀 수 없는 타입이므로 첨자를 써서 일부 글자만 고쳐 쓸 수는 없다. s[0] = 'z' 는 TypeError: 'str' object does not support item assignment 가 되어 거기서 멈추므로 print도 실행되지 않는다. IndexError는 첨자가 범위 밖일 때 나오는 것인데, 여기서는 0이 올바른 범위 안이므로 다른 이야기이다. 내용을 바꾸고 싶을 때는 s = 'z' + s[1:] 처럼 새로운 문자열을 만들어 다시 연결한다. 리스트는 가변(mutable)이므로 같은 방식으로 요소를 고쳐 쓸 수 있다.
문제 24 | 메서드의 반환값
문자열 메서드를 호출하는 다음 프로그램의 출력은 어느 것인가?
s = 'exam's.upper()print(s)print(s.replace('e', 'E'))
1번째 줄이 EXAM, 2번째 줄이 Exam
1번째 줄이 EXAM, 2번째 줄이 EXAM
1번째 줄이 exam, 2번째 줄이 exam
1번째 줄이 exam, 2번째 줄이 Exam
정답D. 1번째 줄이 exam, 2번째 줄이 Exam
문자열 메서드는 원래 문자열을 고쳐 쓰지 않고 새로운 문자열을 만들어 반환한다. 2번째 줄의 s.upper() 는 'EXAM' 을 만들지만 어디에도 대입하지 않았으므로 그 값은 버려지고 s는 'exam' 그대로이다. 따라서 print(s) 의 출력은 exam이 된다. 4번째 줄은 s.replace('e', 'E') 의 반환값을 그대로 표시하므로 Exam이 나오지만, 이것도 s 자체는 바꾸지 않는다. 결과를 남기고 싶을 때는 s = s.upper() 처럼 다시 대입한다. 리스트의 sort() 처럼 그 자리에서 정렬하고 None을 반환하는 메서드와는 대조적이다.
문제 25 | f-string
서식을 지정해 표시하는 다음 프로그램의 출력은 어느 것인가?
n = 2.71828print(f'{n:.2f}')print(f'{"ok"!r}')
1번째 줄이 2.71, 2번째 줄이 'ok'
1번째 줄이 2.72, 2번째 줄이 ok
1번째 줄이 2.718, 2번째 줄이 ok
1번째 줄이 2.72, 2번째 줄이 'ok'
정답D. 1번째 줄이 2.72, 2번째 줄이 'ok'
f-string의 서식 지정 :.2f 는 소수점 이하를 2자리로 반올림해 표시하므로 2.71828 은 2.72가 된다. 버림이 아니므로 2.71이 되지 않으며, 2.718은 :.3f 라고 썼을 때의 값이다. 2번째 줄의 !r 은 변환 지정으로, 값을 repr() 형태로 표시한다. 문자열에 쓰면 따옴표가 붙으므로 'ok' 가 되고, !r 을 붙이지 않으면 ok 만 나온다. 서식 지정 문법은 str.format() 과 공통이므로 '{n:.2f}'.format(n=2.71828) 이라고 써도 같은 2.72를 얻는다.
문제 26 | split
문자열을 분할하는 다음 프로그램의 출력은 어느 것인가?
print('a b c'.split())print('a,b,c'.split(',', 1))
['a', 'b', 'c'] 와 ['a', 'b', 'c']
['a', 'b', '', 'c'] 와 ['a', 'b,c']
['a', 'b', 'c'] 와 ['a', 'b,c']
['a', 'b', '', 'c'] 와 ['a', 'b', 'c']
정답C. ['a', 'b', 'c'] 와 ['a', 'b,c']
split() 을 인수 없이 호출하면 연속된 공백을 하나로 묶은 구분자로 다루어 빈 요소를 만들지 않는다. 그래서 'a b c'.split() 은 3개 요소인 ['a', 'b', 'c'] 가 된다. 구분자를 명시해 'a b c'.split(' ') 이라고 쓰면 공백 하나씩으로 자르므로 빈 문자열이 남아 ['a', 'b', '', 'c'] 라는 4개 요소가 된다. 두 번째 인수는 maxsplit 으로 분할 횟수의 상한을 나타내며 1을 넘기면 처음 1회만 자르므로 ['a', 'b,c'] 가 되고 나머지는 자르지 않은 채 하나의 요소로 뭉친다. 생략하면 ['a', 'b', 'c'] 로 전부 잘린다.
strip() 의 인수는 '제거할 문자의 집합'이며, 양 끝에서 그 집합에 포함된 문자가 이어지는 한 계속 깎는다. 부분 문자열로서의 'x'를 하나만 지우는 것이 아니므로 'xxabxx'.strip('x') 는 양 끝의 x를 모두 떨어뜨려 ab가 된다. 한 글자씩만 지운다고 생각하면 xabx를 고르게 된다. lstrip() 은 왼쪽 끝만을 대상으로 하므로 abxx, rstrip() 은 오른쪽 끝만이므로 xxab가 된다. 인수를 생략하면 공백 문자를 깎는다. 집합으로 다뤄지므로 'xxabxx'.strip('xa') 라고 쓰면 왼쪽 끝의 xx와 a까지 떨어져 b만 남는다.
문제 28 | join과 반복
문자열을 잇는 다음 프로그램의 출력은 어느 것인가?
print('-'.join('abc'))print('ab' * 3)
1번째 줄이 -a-b-c-, 2번째 줄이 ababab
1번째 줄이 abc, 2번째 줄이 ababab
1번째 줄이 a-b-c, 2번째 줄이 ab ab ab
1번째 줄이 a-b-c, 2번째 줄이 ababab
정답D. 1번째 줄이 a-b-c, 2번째 줄이 ababab
join() 은 호출하는 쪽의 문자열을 구분자로 삼아, 전달받은 반복 가능 객체의 각 요소를 잇는다. 문자열도 한 글자씩 꺼낼 수 있는 반복 가능 객체이므로 '-'.join('abc') 는 'a'와 'b'와 'c'를 하이픈으로 이어 a-b-c가 된다. 구분자는 요소와 요소 사이에만 들어가므로 맨 앞이나 끝에는 붙지 않아 -a-b-c- 가 되지 않는다. 구분자가 들어가지 않는 abc가 되는 것은 ''.join('abc') 라고 썼을 때이다. * 연산자는 문자열을 지정한 횟수만큼 반복하므로 'ab' * 3 은 ababab 가 되며 사이에 공백은 들어가지 않는다. ab ab ab 를 원한다면 ' '.join(['ab'] * 3) 이라고 쓴다.
find() 는 부분 문자열을 찾지 못했을 때 -1 을 반환하며 예외가 되지 않는다. 'banana' 에 'z' 는 없으므로 -1 이다. 0은 맨 앞에서 발견되었을 때의 값이므로 찾지 못한 경우와 혼동하지 않도록 해야 한다. index() 는 찾은 위치를 반환한다는 점에서 find() 와 같아, 'banana' 안에서 'n' 이 처음 나타나는 것은 첨자 2 이므로 2 가 된다. 3 이 되는 것은 첨자를 1부터 세어 '3번째 글자'로 읽은 경우, 4는 마지막에 나타나는 위치로, 이를 얻고 싶을 때는 rfind() 나 rindex() 를 쓴다. 둘의 차이는 찾지 못했을 때뿐으로, index() 는 ValueError: substring not found 를 발생시켜 처리를 멈춘다.
문제 30 | raw 문자열
글자 수를 세는 다음 프로그램의 출력은 어느 것인가?
print(len(r'a\nb'), len('a\nb'))
3 4
4 4
3 3
4 3
정답D. 4 3
리터럴 앞에 r을 붙인 raw 문자열에서는 백슬래시가 이스케이프의 시작으로 해석되지 않는다. r'a\nb' 는 a, 백슬래시, n, b의 4글자이므로 len 은 4가 된다. 한편 일반 문자열 'a\nb' 에서는 \n 이 줄바꿈 한 글자로 바뀌므로 a, 줄바꿈, b의 3글자로 len 은 3이다. 둘 다 이스케이프로 세면 3 3, 둘 다 있는 그대로의 글자로 세면 4 4가 되지만, r의 유무로 취급이 달라지는 것이 요점이다. r을 붙여도 타입은 일반 str 그대로이며 특별한 타입이 되는 것은 아니다. 참고로 len('\\') 은 1이며 백슬래시 한 글자를 쓰기 위해 두 개를 겹친 것이다.
연습: 이 페이지의 문제 풀기
무작위로 출제하는 연습 도구입니다(JavaScript가 활성화된 경우에 작동합니다). 위의 문제와 해설은 그대로 모두 읽을 수 있습니다.
※ 해설은 학습용 정보 제공입니다. 시험 출제 범위와 제도는 연도에 따라 바뀌므로, 반드시 시행 기관의 공식 발표를 확인하십시오.
이 페이지는 일본어 원문을 번역한 것입니다. 번역과 원문의 내용이 다를 경우 일본어판이 우선합니다. 일본어 원문 보기