C.W.K.
Stream
Lesson 07 of 07 · published

Input, Output, 그리고 스크립트 실행 — 진짜 프로그램이 되기

~22 min · print, input, sys.argv, stdin, stdout, stderr, main, 스크립트

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

print() — 생각보다 옵션 많아

print() 는 모든 Python 프로그래머가 처음 만나는 함수, 그리고 대부분이 print("hello") 너머를 안 봐. 알아둘 가치 있는 optional 키워드 인자 4 개:

  • sep — 여러 인자 사이의 구분자. default 는 공백 한 칸. print("a", "b", sep="|")a|b 출력.
  • end — 출력 후 붙이는 것. default 는 "\n" (줄바꿈). print("hi", end="")hi 만 출력, 줄바꿈 X.
  • file — 어디로 쓸지. default 는 sys.stdout. 에러 메시지엔 sys.stderr, 또는 열린 파일 객체.
  • flush — 출력 즉시 보이게 강제. progress bar 나 pipe 출력에 유용.

input() — 사용자한테서 한 줄 읽기

input(prompt) 가 prompt 보여주고, 사용자가 한 줄 타이핑할 때까지 기다리고, 타이핑한 거 *문자열로* 반환. *항상* 문자열 — 숫자 필요하면 변환해야 — int(input("age: ")).

표준 입력이 EOF 도달하면 (Unix Ctrl-D, Windows Ctrl-Z + Enter), input()EOFError raise. 스크립트가 끝날 수도 있는 pipe 입력 받으면 try/except 로 감싸 — try: line = input() except EOFError: ....

sys.argv — 첫 명령줄 인터페이스

python myscript.py foo bar baz 실행하면, 값 ["myscript.py", "foo", "bar", "baz"]sys.argv 에 들어가. sys.argv[0] 은 *항상* 스크립트 이름; sys.argv[1:] 가 실제 인자.

일회성 스크립트엔 이거로 충분. 진짜 CLI 도구 — 인자 파싱, help 텍스트, 타입 강제, 서브커맨드 — 엔 argparse 또는 typer (CLI 트랙). 근데 sys.argv 직접 아는 게 기초 — 모든 상위 CLI 라이브러리가 이 위에 빌드.

스크립트 vs 모듈 — `__name__ == "__main__"` idiom

모든 Python 파일에 built-in 변수 __name__ 있어. 파일을 *직접 실행* 하면 (python myscript.py), __name__ 이 문자열 "__main__". 다른 모듈이 *import* 하면, __name__ 이 모듈 이름 (확장자 .py 뺀 파일명).

이게 중요한 idiom 가능하게 해 — if __name__ == "__main__": 블록. 안의 코드는 *직접 실행* 시에만 돌고, *import* 시엔 X. 한 파일이 *쓸 만한 스크립트* 와 *import 가능한 라이브러리* 를 동시에 가능, import 시 이상한 부작용 없이.

원칙: 뭔가 의미 있는 일 하는 모든 Python 스크립트는 *실행 코드* 를 if __name__ == "__main__": 아래 박아야 해. 함수와 클래스는 모듈 top-level 에 있어도 됨 (그래야 import 가능). 실제 *이거 돌려* 로직은 gated. 비용 0, 어느 날 누군가 (또는 미래의 자신) 그 스크립트의 함수 하나 import 하고 싶을 때 살려줘.

세 표준 stream — stdin, stdout, stderr

모든 실행 중 프로그램에 default stream 셋, sys.stdin, sys.stdout, sys.stderr 로 접근. print() 가 default 로 stdout 에 씀. input() 이 stdin 에서 읽음. 에러와 경고는 *stderr 로 가야 해* — 그래야 pipe 와 redirect 가 일반 출력과 안 섞여.

이게 중요한 이유 — Unix pipe 는 stdout 만 옮겨. python myscript.py | grep hello 가 stdout 만 grep. 에러는 stderr 로 가서, 출력이 pipe 되거나 파일로 redirect 돼도 *터미널에 그대로 보여*.

자기참조: cwkPippa 의 CLI 스크립트 (scripts/ 아래) 다 같은 패턴 — 일반 출력은 stdout, 상태 메시지와 경고는 stderr, 성공이면 exit code 0, 실패면 non-zero. 이게 heartbeat 스케줄러가 *작업이 깔끔히 돌았나* 자동으로 알 수 있게 해. 그 규율 없으면 스케줄러가 *뭐가 동작했나* 알기 위해 로그를 파싱해야 해.

스크립트 실행 — 4 가지 방법

Python 파일 있으면, 흔한 4 실행 방법:

  • python myscript.py — 명시적, 어디서나 동작
  • python -m mymodule — 모듈을 스크립트로 실행 (Python 의 import 기계 사용)
  • ./myscript.py — 맨 위에 shebang 줄 (#!/usr/bin/env python3) 필요 + 파일 실행 가능 표시 (chmod +x myscript.py). Unix/macOS 만.
  • python -c "print('hello')" — 파일 없이 인라인 명령 실행. 한 줄짜리, Makefile snippet 에 유용.

요약

이제 명령줄 인자 받고, stdin 에서 읽고, stdout/stderr 에 적절히 쓰고, 라이브러리로도 import 가능한 Python 스크립트 작성 가능. 그게 *진짜 Python 프로그램* 의 모양. lesson 8 부터는 이 모양 위에 쌓여.

Pythonic Way: 스크립트 진입점엔 *항상* if __name__ == "__main__":. 에러는 *항상* stderr 로 (print(..., file=sys.stderr)). 실패 시 *항상* sys.exit(1), 그냥 return X. Unix 관습 존중하는 도구는 다른 도구와 합성 가능; 안 그런 도구는 외딴 섬.

Code

print() — 4 optional 인자 전부·python
>>> print("a", "b", "c")                         # default sep=' ', end='\n'
a b c

>>> print("a", "b", "c", sep="|")
a|b|c

>>> print("loading", end="")                     # 줄바꿈 X — progress 에 유용
loading
>>> for i in range(3):
...     print(".", end="", flush=True)            # flush 가 즉시 출력 강제
...
...

>>> import sys
>>> print("앗", file=sys.stderr)                  # 에러 메시지는 stderr
앗
input() — 한 줄 읽음, *항상* str 반환·python
name = input("이름? ")
age_str = input("나이? ")
age = int(age_str)               # input 은 항상 str — 필요하면 변환

print(f"안녕 {name}, 내년엔 {age + 1} 살.")

# EOF 처리 (예 — pipe 입력 끝남):
try:
    line = input()
except EOFError:
    print("입력 끝.", file=sys.stderr)
sys.argv — 명령줄 인자 첫 만남·python
# greet.py
import sys

if len(sys.argv) < 2:
    print(f"사용법: {sys.argv[0]} <이름>", file=sys.stderr)
    sys.exit(1)

name = sys.argv[1]
print(f"안녕, {name}!")

# 실행:
# $ python greet.py 피파
# 안녕, 피파!
# $ python greet.py
# 사용법: greet.py <이름>
# $ echo $?      # exit code
# 1
__name__ == '__main__' — 한 파일에 스크립트 + 라이브러리·python
# greeter.py
def make_greeting(name):
    """친근한 인사 반환."""
    return f"안녕, {name}!"

def main():
    import sys
    if len(sys.argv) > 1:
        print(make_greeting(sys.argv[1]))
    else:
        print(make_greeting("world"))

if __name__ == "__main__":
    main()

# 이제 이 파일 두 가지로 동작:
# (1) 스크립트로:        python greeter.py 피파
# (2) 라이브러리로:       from greeter import make_greeting
#                         make_greeting("피파")  # '안녕, 피파!'
stdin / stdout / stderr — Unix 스타일 합성·python
# uppercase.py — stdin 읽고 대문자로 stdout 에 씀
import sys

for line in sys.stdin:
    print(line.rstrip().upper())

# 다른 Unix 도구와 합성:
# $ echo 'hello world' | python uppercase.py
# HELLO WORLD

# $ cat names.txt | python uppercase.py | sort
# (full Unix 파이프라인 — Python 스크립트가 한 단계일 뿐)

# 에러는 stderr 로 — stdout 이 redirect 돼도 보여:
# $ python uppercase.py < input.txt > output.txt
# (sys.stderr 로 print 한 건 그래도 터미널에 떠)

External links

Exercise

작은 스크립트 repeat.py 작성 — 명령줄 인자 두 개 받기 (문자열 + 숫자), 그 문자열을 *숫자 횟수만큼* 한 줄씩 출력. sys.argv 직접 사용 (argparse 아직 X). if __name__ == "__main__": guard 박음. 인자가 잘못되면 (없거나 정수 X) sys.stderr 로 출력 + exit code 1. 그 다음 테스트 — 출력을 wc -l 로 pipe 해서 count 가 통과한 숫자랑 일치하는지 확인.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.