[python] input()함수와 sys.stdin.readline() 함수에 대한 고찰

gigagookbob·2025년 10월 21일

호기심 백과사전

목록 보기
2/3
post-thumbnail

2025/5/21에 작성한 글을 블로그로 옮긴 내용입니다.


이 글을 작성하게 된 계기는, 백준 코딩 테스트 문제 2751번 수 정렬하기 2 를 풀며 입력값을 받는 방식에 대해 의문점을 가지게 되어 작성하게 되었습니다.

Q1. 그래서 뭐가 더 빨라요?

결과부터 말씀드리면 sys.stdin.readline() 함수가 더 🐇빠르고, input() 함수가 더 🐢느려요.

아래 코드와 실행 결과는 테스트 데이터 1,000만 개에 대해 파일 읽기를 시도해 각 각 한줄 씩 읽었을 때 걸린 시간이에요 😱

import sys
import time

# 테스트용 임시 파일 만들기
with open("test.txt", "w") as f:
    for i in range(10000000):
        f.write(f"{i}\n")

# 1) input() 사용
sys.stdin = open("test.txt")
start = time.time()
for _ in range(10000000):
    _ = input()
print("input()함수🐢가 걸린 시간:", time.time() - start)

# 2) sys.stdin.readline() 사용
sys.stdin = open("test.txt")
input = sys.stdin.readline
start = time.time()
for _ in range(10000000):
    _ = input()
print("readline()함수🐇가 걸린 시간:", time.time() - start)
➜ python test_read_file.py
input()함수🐢가 걸린 시간: 2.416167974472046
readline()함수🐇가 걸린 시간: 0.5037460327148438

Q2. 왜 빠른데요?

이유만 단순하게 말씀드리자면, input()함수는 여러분이 생각하는 것보다 상당히 많은 일들을 하고 있어서 단순히 “읽기”만 하지 않아요. 그래서 “한 줄 읽기”에만 집중하는 sys.stdin.readline() 함수보다 느리답니다 😝

Q3. input() 함수가 하는 일들이 도대체 뭐가 있는데요?

https://docs.python.org/ko/3.13/library/functions.html#input

질문이 약간 “너가 하는게 뭐가 있는데 이렇게 늦냐” 라는 느낌이 있는데요 😅 이것을 알기 위해서는 input() 함수를 하나씩 뜯어보자구요! 🌞 어렵지 않으니 찬찬히 글을 읽어보면 충분히 따라오실 수 있을거에요! 😁

파이썬 공식 문서에 따르면, 함수의 매개변수로 prompt를 받을 수도 있고, 받지 않을 수도 있어요.

매개변수인 prompt를 받으면 후행 개행 문자 (”\n”)를 붙이지 않고 표준 출력에 출력해줘요.(정확한 표현은 표준 출력에 쓴다에요)

지금까지 설명해드린 문장에서 “prompt”, “표준 출력”, “후행 개행 문자”와 같은 단어가 도대체 무슨 말이야~ 싶을 것 같아요~!

간단하게 설명하자면, 사용자에게 입력을 요청할 때 화면에 보여주는 메세지 문자열인 “prompt”, 터미널이나 콘솔 같은 기본 출력 스트림인 “표준 출력”, 문자열 끝에 붙는 줄바꿈 문자인 “\n” 라고 한답니다 😊

스트림(stream)은 또 뭔지 궁금하실 것 같은데요.. 🧐

간단히 말하면, 프로그램이 화면(또는 파일·네트워크)로 텍스트나 바이너리 데이터를 전달할 때 사용하는 통로라고 생각하시면 됩니다 🛣️ 컴퓨터는 사용자에게 이 결과를 보여줘야 하니까요 😊

다시 돌아와서, 반대로 prompt를 받지 않으면 어떤 일이 일어날까요? 사실 딱히 아무 일이 일어나지 않습니다. prompt에 입력된 값이 없기 때문에, 이 경우에는 아무것도 출력해주지 않고 입력을 받을 준비를 하고 있게 되는거에요.

input() 함수는 단순히 입력만 받는 친구는 또 아니에요. 입력에서 한 줄을 읽고, 문자열로 변환해서 해당 문자열 끝에 있는 개행 문자(”\n”)를 제거해서 리턴해준답니다.

여기까지 이해가 잘 가셨다면, input() 함수가 뭘 하는지는 큰 범위에서는 알고 있다라고 말할 수 있겠네요!

하지만 input()함수의 동작은 생각보다 이렇게까지 간단하지는 않아요 🥹

input()함수가 실행되었을 때, 사용하는 사람인 우리(사용자)를 위해서 몇 가지 추가적으로 해주는 일들이 있는데요, 아래 나열된 내용을 간단히 읽어보실까요? 💁

  • 프롬프트 출력(입력 프롬프트 존재 시)
  • 후행 개행 문자(”\n”) 제거
  • readline 모듈을 활용한 편집/히스토리 기능 제공
  • 입력 스트림에서 EOF(End Of File)을 만나면 EOF 예외처리
  • auditing event 처리

단순히 사용자에게 입력을 받아서 해당 입력을 출력해주는 줄만 알았는데, 생각보다 많은 일들이 벌어지고 있었네요! 🥳

Q3-1. input 함수가 하는 각각의 일들이 구체적으로 뭔지 궁금해요

input() 함수가 sys.stdin.readline()함수와 비교했을 때 느린 이유를 알기 위해 input()함수가 해주는 각각의 일들에 대해 너무 많은 것들을 아실 필요는 없지만, 어떤 일들을 하는지 한 번 둘러보신다면 Aha-Point 가 더 늘어날거에요! 지금부터 차근차근 알아볼까요? ☺️

readline 모듈의 사용

https://docs.python.org/ko/3.13/library/readline.html

readline 모듈은 대화형 파이썬 셸에서 탭 자동 완성, 이전에 입력한 명령 불러오기, 키 설정 같은 편의 기능을 든든히 챙겨주는 친구예요.

탭 자동 완성을 도와줘서 식별자나 변수 이름을 일일이 다 타이핑하지 않아도 되고,

입력 히스토리를 관리해줘서 화살표 키만으로 과거 명령을 쭉 살펴볼 수 있으며,

키 바인딩을 바꿀 수 있게 해줘서 vi 스타일, emacs 스타일 등 원하는 키 조작 모드를 선택할 수 있게 해 주거든요.

우리가 python 명령어를 통해 대화형 인터프리터로 접근할 수 있는데, 사진과 같은 화면을 많이 보셨죠?

이곳에서 탭 키로 자동 완성도 해 보고, 위·아래 화살표로 이전에 입력한 명령을 쭉 불러와서 편리하게 작업할 수 있게 해주는 마법 같은 기능이 바로 readline 모듈 덕분이랍니다 😃

잘 이해가 안 가시는 분들도 있을 것 같아 간단한 예시를 들어볼게요.

  • 철수는 cmd 창에 python이라고 작성해 엔터를 눌러 대화형 인터프리터로 들어갔어요.
  • 그리곤 다음과 같이 입력하고 input() 엔터를 눌렀어요
  • 입력을 받기를 기다리는 커서가 나오고 철수는 방향키 위 아래를 요리조리 눌러봤어요
  • 우와! 이전에 작성했던 input() 텍스트가 다시 불러와 졌어요! 🤹

EOF 예외처리

EOF는 말 그대로 해석하면 End of File로 파일의 끝을 의미해요. 그런데 이렇게만 알고 넘어가면 재미가 없죠?

EOF는 파일이나 입력 스트림을 읽을 때, 더 이상 읽을 내용이 없다는 것을 알려주기 위해 사용되는데요, 가령 input을 받고 있다가 unix/macOS 계열에서는 Ctrl+D로, Windows에서는 Ctrl+z로 EOF를 발생시켜 끝낼 수 있어요.

input() 함수는 이러한 상황에 대해 예외처리를 해 놨는데요,

아래 코드를 실행 하여 EOF를 발생시켜보면

💡
while True:
    line = input()
    if line == "":
        break
    print(line)

다음과 같이 예외처리를 해준답니다 🦾

Auditing event 처리

auditing event는 한글로 직역하면 “감사 이벤트” 라고 하는데요, 말 그대로 어떤 행위를 계속해서 추적하는 의미를 담고 있어요. 보안이 취약한 파이썬에서 일종의 보안 체계를 확보했구나 라는 생각이 들었답니다!

호출에 의해서 발생하는 모든 이벤트는 파이썬 공식 문서에 표로 보기 좋게 잘 정리되어 있어요! 👀

https://docs.python.org/ko/3.13/library/audit_events.html#audit-events

(PEP 578에서 Audit Hook을 제안했어요 🎶)

그래서 input() 함수 실행 시 입력을 읽기 전에 builtins.input라는 이름의 auditing event를, 인자로 prompt를 포함하여 발생시켜줘요.

입력을 성공적으로 읽은 후에는 builtins.input/result라는 auditing event를, 결과 문자열을 인자로 발생시켜줘요.

이와 같은 과정을 통해 input() 함수를 쓰면 어디서 어떻게 입력을 읽었는지와 어디서 어떻게 출력되었는지 이벤트로 기록되기 때문에, 보안적으로 조금은 안전해지겠구나! 라는 생각을 하게 되었답니다 🔐

Q4. 그래서 결론은요?

input() 함수는 우리가 막연하게 알고 있는 개념이었던 “입력 한 줄을 읽는다”라는 것보다는 생각보다 많은 일들을 하고 있었다는 것, 이것이 여러 입력 내용을 한 줄씩 읽는 데에 영향을 준다는 것만 알고 넘어가시면 좋다고 생각합니다 😎

Q5. 그럼 sys.stdin.readline() 함수는 뭘 하는데요?

우선 sys, stdin, readline() 각각의 개념에 대해서 짚고 넘어가는게 좋을 것 같아요!

간단하게 설명하면 아래와 같이 설명할 수 있는데요!

  • sys 모듈은 파이썬 인터프리터와 시스템 환경 간 상호작용을 관리하는 핵심 라이브러리
  • sys.stdin은 파이썬 인터프리터가 “표준 입력”으로 사용하는 파일 객체(File-like object)
  • readline() 은 파일 객체의 “한 줄 읽기” 메서드

갑자기 또 여러 개념들이 나와서 헷갈리시죠? 저와 함께 차근차근 알아봐요 😁

Q5-1. 저렇게만 써 놓은 sys 모듈이 뭔지 모르겠어요

sys 모듈의 개념 중, “파이썬 인터프리터와 시스템 환경 간 상호작용을 관리하는”에 집중해볼까요?

파이썬 코드가 운영체제와 직접 주고받아야 할 정보 - 예를 들어 명령줄 인자(sys.argv)를 처리하고, 표준 입출력 스트림(sys.stdin, sys.stdout)을 제어하며, 모듈 검색 경로(sys.path)를 관리하고, 종료 상태(sys.exit())를 반환하는 등의 기능을 통해 파이썬 인터프리터와 시스템 환경 간의 다리 역할을 한다고 할 수 있어요!

즉, 파이썬 코드를 작성해 시스템 레벨의 작업을 직접 수행할 수 있다는 뜻이에요! 🤖

Q5-2. 그럼 이 sys 모듈이랑 readline() 함수랑 뭔 관계인데요?

잠시만요! 아직 한 단계가 남았어요 😏 다음 질문에서 stdin 객체(object)에 대해 설명하고 넘어가는게 좋을 것 같네요 😁

Q5-3. 알겠어요. 그럼 sys.stdin 은 또 뭔가요?

sys.stdin은 아까 봤던 sys모듈에서 제공하는 “표준 입력 스트림”객체에요. Standard Input Stream이라고 해서 stdin으로 줄이는 거랍니다 😊

어라 그런데 “객체” 라는 말에 조금 위화감을 느끼지 않으셨나요?

정확히 말하면 sys.stdin은 표준 입력 스트림을 “추상화”한 file-like object에요.

file-like object가 뭔지 모르겠다구요? 파이썬 공식 문서에는 다음과 같이 정의되어 있는데요,

공식 문서라는 놈들이 정말로 이렇게 적어놨어요 😭 하지만 낙담하지 말고 제 설명을 찬찬히 따라와 보세요!

파일 객체(file object)는 파일류 객체 (file-like objects)나 스트림 (streams) 이라고도 불린다고 해요! 그러므로 저는 동일 선상에 놓고 설명할게요 😉

파일 객체는 실제 디스크 파일, 표준 입출력, 메모리 버퍼, 네트워크 소켓, 파이프 등 데이터를 주고받을 수 있는 모든 “스트림(stream)” 자원을 다룰 수 있도록 추상화를 제공하는 친구에요 😎

스트림(stream)은 데이터가 연속적으로 흐르는 통로 또는 경로를 생각하시면 머릿속에 떠올리기 쉬울거라고 생각합니다! 👍

컴퓨터에서는 여러 가지 데이터가 왔다갔다 하는데요, 이 데이터를 왔다 갔다 하는데 쓰이는 통로가 스트림(stream) 입니다 😁

즉 이러한 입력 통로를 추상화한 것이 바로 sys.stdin 객체에요(file-like object). 이제 조금은 이해가 가셨을까요?

표준 입력 스트림(standard input stream)을 추상화함으로써, 이를 사용하는 사람은 키보드, 파일, 파이프 등 실제 입력 장치나 OS 레벨의 버퍼링·시스템 호출 같은 세부 구현 방식을 깊이 알지 못해도, 추후 설명할 readline() 같은 메서드만으로 데이터를 편리하게 읽어올 수 있는 것이에요!

Q6. 그래서 도대체 sys.stdin.readline() 함수는 뭡니까?

휴~~~😮‍💨😮‍💨😮‍💨 너무 긴 여정을 거쳤으니, 이제 정말 마지막 스퍼트를 달려볼까요?!

sys 모듈은 파이썬 인터프리터와 운영체제(시스템) 사이에 다리 역할을 할 수 있는 도구였죠?!

sys.stdin class는 파이썬 인터프리터가 “표준 입력(standard input)”으로 사용할 때 연결되는 file-like object라고 했어요!

stdin 클래스를 통해 사용할 수 있는 readline() 함수는 이 file-like object가 제공하는 “한 줄 읽기” 전용 메서드에요!

엔터(개행 문자 \n)를 포함한 한 줄 전체를 그대로 읽어서 문자열로 반환한답니다 😏

여러분이 실제로 readline() 함수로 파일 한줄을 읽으면 뒤에 개행문자도 그대로 같이 읽힌답니다 🙈

만약 이게 싫다면 rstrip() 같은 함수로 뒤에 개행 문자를 지워줄 수 있겠죠?! 💁

readline()함수가 input()함수보다 빠른 핵심적인 이유는 내부적으로 단순히 C 레벨의 fgets() 같은 함수 호출만 하므로 오버헤드가 거의 없답니다 😎

(오버헤드란 주요 작업 이외에 추가로 소요되는 자원을 의미해요 🤯)

실제 구현이 보고싶으시다면 https://github.dev/python/cpython/tree/main 로 접속하세요!

그리고 255번째줄부터 쭉 내리다 보면 336번째줄에 my_fgets()를 사용해서 실제로 C의 함수를 호출하는 모습을 볼 수 있답니다 👀 👀

파이썬의 표준 구현체 cpython 내부 코드

my_fgets 함수를 사용하는 모습

이러한 이유로 빠른 거였군요!

input() 함수와 차이점을 딱 한줄로 요약하면 다음과 같이 말할 수 있겠습니다.

_ = input()               # → prompt 출력, 개행 제거, 히스토리/편집·감사 이벤트까지 다 합니다
_ = sys.stdin.readline()  # → 그냥 “\n” 포함해서 한 줄만 콜!

input()함수에서나 존재했던 prompt나 trimming, 히스토리, audit 같은 부가 기능 전혀 없고, 버퍼링·시스템 호출 외에는 추가 작업이 없으니, “읽기”에만 집중 가능하고, 그래서 수천만 줄 읽는 코드에서 차이가 확연하게 드러나는 거죠! 🐇🐇🐇


지금까지 sys.stdin.readline() 함수가 input() 함수보다 더 빠른 이유에 대해서 알아봤습니다.

긴 여정을 함께해주셔서 감사합니다 ☺️

질문, 태클, 다른 생각 등 모든 피드백 환영합니다!

profile
선명한 기억보다 희미한 기록으로

0개의 댓글