Python 코딩 테스트 : 입력

RookieAND·2022년 7월 3일
6

CodingTest

목록 보기
1/3
post-thumbnail

📖 Before Start

이 글은 Python 으로 처음 코딩 테스트를 진행하는 분들께 유용합니다.

처음 코딩 테스트 문제를 호기롭게 도전했을 때, 나를 가장 당황스럽게 만들었던 요소는
복잡하고 어려운 함수도 아니고, 문제 풀이에 쓰이는 알고리즘도 아닌 입출력 처리 였다.

올해 3월, 처음으로 Python을 입문하고 한 달도 채 되지 않아 문제를 풀어보려 하니,
기본적인 입출력도 하지 못해 미친듯이 코테 관련 포스트를 찾아보았던 기억이 난다.

따라서 오늘은 비록 비루한 실력이지만, 추후 Python으로 코딩 테스트를 시작하는 분께
조금이라도 도움이 되었으면 하는 바램에서 이 포스트를 작성하고자 한다.

✒️ Standard Input

input() 보다는, sys 라이브러리에서 제공하는 sys.stdin.readline() 를 사용하자.

백준 15552번 문제인 빠른 A+B 문제에서는 처음으로 빠른 입출력 방식을 요구한다.
https://www.acmicpc.net/problem/15552 에서 해당 문제의 전문을 열람할 수 있다.

import sys

count= int(sys.stdin.readline())
data = []
for i in range(count):
	data.append(sum(map(int, sys.stdin.readline().split())))
    
for x in data:
	print(x)

Java 에서는 ScannerSystem.out.println 보다는 BufferedReader 를 써야하고,
Python 에서는 input() 대신 sys 라이브러리의 sys.stdin.readline() 을 권장한다.

그런데, 왜 많은 양의 입출력을 시행할 경우에는 input() 함수가 더 느린 걸까?
그에 대한 해답은 두 입력 방식의 작동 과정을 올바르게 이해하면 알 수 있다.


⌨️ input() Function

input() 함수의 경우 사용자의 입력을 읽어온 후, 아래와 같은 처리 과정을 거친다.

  • 먼저, 프롬프트로부터 사용자의 입력을 받음.
  • 입력 받은 값 중에서, 개행문자 \n 를 제거함.
  • 이후 해당 값을 문자열로 변경한 후, 이를 return 함.

또한 input() 함수의 경우, 더 이상 입력이 주어지지 않을 때 EOFError 를 띄운다.


⌨️ sys.stdin Object

sys.stdininput() 함수와 달리 File Object, 즉 하나의 객체이다.
하단의 코드를 실행시켰을 경우, sys.stdin 객체의 속성을 열람할 수 있다.

dir(sys.stdin)

>>> ['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', 
	 '__dict__', '__dir__', ..., 'write', 'writelines']

그리고 readline 의 경우 sys.stdin 객체에서 지원하는 메소드이다.
또한 readlineEOF 에 도달할 시 에러가 아닌 빈 문자열을 반환한다.

주의할 점은, readline 의 경우 개행문자 \n 까지 받아온다는 점이다.
따라서 이를 제거하고 싶다면 strip() 함수를 추가로 실행해주어야 한다.


💡 Which one is more faster?

input() 함수는 사용자의 입력을 받아 문자열로 변환시키는 과정이 필요하지만,
sys.stdin 의 경우 사용자의 입력을 Buffer 에 저장한 후 요청이 올때마다 읽는다.

이러한 이유로 sys.stdin.readlineinput() 함수보다 더 빠르게 동작하는 것이다.
불필요한 전처리 과정 없이 바로바로 Buffer 에서 한 줄씩 값을 읽어오기만 하면 되니까.

하나 덧붙이자면 sys.stdin.readline 메소드를 변수에 할당시키는 방법도 있다.
왜냐하면 파이썬에서의 함수는 1급 객체 (First-Class Object) 로 취급되기 때문이다.

따라서 다음과 같이 코드를 작성하면, 보다 효율적으로 입출력 처리가 가능하다.

import sys

read = sys.stdin.readline
count = int(read())
data = [sum(map(int, read().split())) for _ in range(count)]
 
for x in data:
	print(x)

한눈에 봐도 코드의 가독성이 기존에 비해 월등히 좋아졌다는 느낌이 팍팍 든다.
그럼 이제 본격적으로 여러 케이스에 대한 입력을 어떻게 처리하는지 설명하겠다.

✒️ Example of Code

문제에서 요구하는 다양한 입력 방식에 따른 코드를 안내하는 파트다.

📌 N개의 정수를 한 줄로 입력 받았을 경우

import sys

read = sys.stdin.readline
N, M, K = map(int, read().split())

map() 함수는 여러개의 데이터를 다른 형태로 변환시키기 위해서 사용되는 함수다.
따라서 read().split() 을 통해 나온 List 내의 요소들을, int() 함수로 변환하여
최종적으로 나온 정수들을 순차적으로 변수에 저장하는 방식이다.


📌 N개의 정수를 한 줄로 입력 받아 List에 저장할 경우

import sys

read = sys.stdin.readline
data = list(map(int, read().split()))

상단의 방식과 거의 동일하나, 약간의 차이점이 있다면 list() 함수의 유무다.
map() 함수는 map 객체를 리턴하기에, 이를 다시 List 로 변환해주어야 한다.


📌 N개의 정수를 여러 줄에 걸쳐 입력 받아 List에 저장할 경우

import sys

read = sys.stdin.readline
N = int(read())
data = [int(read()) for _ in range(N)]

여기서는 빈 List 를 생성한 후, append() 함수를 통해 값을 추가해도 된다.
하지만 List Comprehension 기법을 쓴다면 보다 더 간결하게 코드를 쓸 수 있다.


📌 N개의 문자열을 여러 줄에 걸쳐 입력 받아 List에 저장할 경우

import sys

read = sys.stdin.readline
N = int(read())
data = [read().strip() for _ in range(N)]

대부분의 문자열 처리의 경우 개행문자 \n 를 제거해야 하는 경우가 많다.
따라서 strip() 함수를 통해 문자열에 붙은 개행문자를 없애버리면 된다.


📌 N개의 정수를 여러 줄에 걸쳐 입력 받아 이차원 배열에 저장할 경우.

import sys

read = sys.stdin.readline
N = int(read())
matrix = [list(map(int, read().split())) for _ in range(N)]

이차원 배열의 경우 그래프 문제를 풀기 위해 주어진 입력을 토대로 만드는 경우가 많다.
이 경우에도 List Comprehension 기법을 사용하여 한 줄로 이차원 배열 생성이 가능하다.

📖 Conclusion

나름 열심히 정리한다고 했는데, 괜찮은지 모르겠다.

다음 포스팅은 아마 표준 출력 과 관련된 내용을 작성하지 않을까 싶다.
물론 print() 함수를 쓰는 것이 일반적이나, unpacking 기법에 대한 내용도 적을 것이다.

코드나 설명에 오류가 있다면 댓글로 제보 부탁드립니다. 감사합니다.

profile
항상 왜 이걸 써야하는지가 궁금한 사람

0개의 댓글