Skip to content
This page has been auto-translated and may contain errors.View in English

출력과 입력

코드 첫 줄부터 사용하게 될 두 가지 도구: print()는 터미널에 값을 표시하고, input()은 사용자로부터 텍스트를 받습니다. 간단하지만, 동작 방식을 알아두면 초반에 겪을 수 있는 몇 가지 당황스러운 상황을 피할 수 있습니다.

print()input()은 파이썬의 표준 터미널 I/O 함수입니다. 두 함수 모두 처음 보기보다 설정 가능한 옵션이 많습니다. print()는 값을 어떻게 연결하고 출력을 어디서 끝낼지 제어하는 인자를 받습니다. input()은 항상 문자열을 반환하므로, 사용자로부터 받은 모든 값을 어떻게 다룰지가 결정됩니다.

print()sys.stdout을 감싸고, input()sys.stdin을 감쌉니다. 둘 다 텍스트만 다루며, 인코딩은 스트림의 코덱에 위임하고, 기본적으로 출력을 버퍼링합니다. stdout과 stderr의 분리, 그리고 flush 제어는 실제 프로그램에서 중요합니다.

파이썬이 코드를 실행하는 방식

파이썬은 코드를 위에서 아래로, 한 줄씩, 작성한 순서 그대로 실행합니다. 건너뛰는 일은 없습니다. 작성한 순서가 실행되는 순서입니다. 항상요.

python
city = "서울"
print(city)
print("인구: 970만 명")

city가 먼저 할당됩니다. 첫 번째 print가 실행됩니다. 두 번째 print가 실행됩니다. 매번 이 순서대로요.

이게 중요한 이유는, 할당하기 전에는 변수를 사용할 수 없기 때문입니다. 파이썬은 아직 그 변수를 본 적이 없기에 에러를 발생시킵니다:

python
print(country)   # NameError: country가 아직 정의되지 않았음
country = "한국"

프로그램이 커질수록 이 점을 명심하세요: 사용하려는 모든 것은 사용하기 전에 정의되어 있어야 합니다.

파이썬은 순차 실행을 사용합니다: 각 문장은 마주치는 순간에 평가되며, 파일을 위에서 아래로 한 번 훑으면서 진행됩니다. 파일 전체를 미리 스캔하지 않습니다. 할당되기 전에 이름을 참조하면 정확히 그 줄에서 NameError가 발생하지, 그 이전에 발생하지 않습니다.

python
city = "서울"
print(city)             # 동작함: city는 이미 바인딩되어 있음
print(country)          # NameError: 아직 할당되지 않음
country = "한국"

규칙은 간단합니다: 의존하는 대상은 그것을 사용하는 줄 이전에 정의되어 있어야 합니다.

파이썬의 실행 모델은 단일 패스 순차 평가입니다. 이름 해석은 파싱 시점이 아닌 평가 시점에 일어납니다. 파서는 이름을 해석하지 않은 채 바이트코드를 만들기 때문에, NameError는 문법 오류가 아니라 런타임 예외입니다. 파이썬에는 호이스팅(JavaScript의 var와 달리)도, 전방 선언(C와 달리)도 없습니다. 이름은 바인딩되는 그 순간부터 사용 가능해지며, 그 전에 참조하면 예외가 발생합니다.

python
print(country)   # 문법 오류가 아닌 런타임 NameError
country = "한국"

출력하기

print()는 파이썬이 여러분에게 응답하는 방법입니다. 어떤 값이든 전달하면 그 값을 표시합니다. 주는 것이 무엇이든 자동으로 텍스트로 변환합니다.

print()는 각 인자를 str()을 통해 문자열로 변환하고, 구분자(기본값은 공백)로 연결한 다음, 결과에 줄바꿈을 붙여 표준 출력에 씁니다. 기본값을 이해하면 선택적 인자를 다루기가 쉬워집니다.

print()의 전체 시그니처는 print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)입니다. *objects 컬렉터는 임의 개수의 위치 인자를 받아 각각에 대해 str()을 호출합니다. sepend는 포매팅을 제어하고, file은 출력을 임의의 쓰기 가능한 스트림으로 리디렉션하며, flush는 버퍼를 즉시 비우도록 강제합니다.

python
print("안녕")     # 안녕
print(42)         # 42
print(3.14)       # 3.14
print(True)       # True

여러 값 출력하기

쉼표로 구분하여 여러 값을 한 번에 출력할 수 있습니다. 파이썬은 기본적으로 값 사이에 공백을 넣습니다. 구분자를 sep으로 바꿀 수 있습니다:

여러 개의 위치 인자는 각각 개별적으로 str()로 변환된 후 sep으로 연결됩니다. 기본 sep은 공백 하나입니다. 이를 재정의하면 문자열을 연결하지 않고도 포매팅된 출력을 만들 수 있습니다:

각 위치 인자는 연결되기 전에 개별적으로 str()을 통과합니다. 연결에는 sep이 사용되고, 그 뒤에 end가 추가된 후, 출력 스트림에 한 번의 호출로 전체가 쓰입니다. sep을 재정의하는 것이 수동으로 문자열을 구성하는 것보다 깔끔합니다:

python
name = "민준"
age  = 28
print(name, age)                        # 민준 28
print("이름:", name)                    # 이름: 민준
print("2024", "01", "15", sep="-")     # 2024-01-15
print("a", "b", "c", sep=", ")         # a, b, c

줄 끝 제어하기

print() 호출은 기본적으로 줄바꿈으로 끝나므로, 다음 출력은 새 줄에서 시작합니다. 이를 end로 바꿀 수 있습니다. end=""로 설정하면 다음 print가 같은 줄에서 이어집니다:

end 매개변수는 기본 줄바꿈을 대체합니다. ""로 설정하면 줄바꿈을 억제하고, " "로 설정하면 공백을 두고 같은 줄에 머물며, 다른 어떤 문자열로도 설정할 수 있습니다. sep과 결합하면 문자열을 수동으로 만들지 않고도 대부분의 출력 형식을 만들 수 있습니다:

sepend는 키워드 전용 인자이며 기본값은 각각 ' ''\n'입니다. end=""로 설정하는 것은 부분적인 줄을 출력하고 다음 호출이 이어가게 하는 표준 방식입니다. 진행 표시기나 로그 같은 실시간 출력의 경우, flush=True는 줄바꿈이나 버퍼 채움을 기다리지 않고 버퍼를 즉시 비우도록 강제합니다.

python
print("로딩 중", end="")
print("...")
# 로딩 중...

print("하나", end=" | ")
print("둘", end=" | ")
print("셋")
# 하나 | 둘 | 셋

f-string으로 출력 포매팅하기

메시지를 만드는 가장 깔끔한 방법은 f-string입니다. 여는 따옴표 앞에 f를 붙이고, 변수나 표현식을 중괄호로 감쌉니다. 파이썬이 런타임에 채워줍니다. {} 안에는 어떤 값, 계산식, 메서드 호출이든 넣을 수 있습니다.

f-string은 {} 안의 모든 표현식을 런타임에 평가하고 결과를 문자열로 임베드합니다. 값 뒤에 콜론을 붙이면 포맷 명세가 시작됩니다: 소수점 자리, 정렬, 숫자 포매팅을 제어하는 간결한 문법입니다. 연결보다 빠르고 읽기 쉬우며, 명시적인 str() 호출이 필요하지 않습니다.

f-string(PEP 498)은 각 {}format(value, spec)을 호출하는 바이트코드로 컴파일하며, 이는 value.__format__(spec)에 위임됩니다. __format__을 구현하는 모든 클래스는 f-string 안에서 자신의 표시 방식을 제어합니다. 변환 플래그 !r, !s, !a는 format 호출 전에 각각 repr(), str(), ascii()를 적용합니다. !r이 가장 유용합니다: 문자열 주위에 따옴표를 표시하고 보이지 않는 문자를 보이게 만듭니다.

python
name  = "민준"
score = 980

# 연결: 거추장스럽고, 숫자에는 str()이 필요함
print("선수: " + name + ", 점수: " + str(score))

# f-string: 읽기 쉽고, 수동 변환이 없음
print(f"선수: {name}, 점수: {score}")

{} 안에는 어떤 표현식이든 넣을 수 있습니다: 산술, 메서드 호출, 포맷 명세:

python
price = 49.99
tax   = 0.2
total = price * (1 + tax)

print(f"합계: {total:.2f}")           # 합계: 59.99
print(f"이름: {name.upper()}")        # 이름: 민준
print(f"2 + 2 = {2 + 2}")             # 2 + 2 = 4

: 뒤의 포맷 명세는 값이 어떻게 표시될지 제어합니다:

python
ratio = 0.8765
count = 1234567
label = "매출"

print(f"{ratio:.1%}")       # 87.7%
print(f"{count:,}")         # 1,234,567
print(f"{label:>12}")       # "          매출"

:.2f는 "소수점 둘째 자리까지"를 의미합니다. 가격과 측정값에 끊임없이 사용하게 됩니다. 나머지는 필요할 때 찾아 쓰면 됩니다. 핵심: {} 안에는 변수 이름뿐 아니라 무엇이든 들어갈 수 있다는 점입니다.

:.2f:.0%는 대부분의 포매팅 필요를 충족합니다. 너비와 함께 사용하는 정렬 지정자(>, <, ^)는 깔끔한 표 형식의 출력을 만듭니다. 일반적인 패턴은 {value:[align][width][.precision][type]}입니다. 구성 요소를 인식하게 되면 모든 조합을 외우지 않고도 어떤 명세든 읽을 수 있습니다.

명세 문자열은 그대로 value.__format__(spec)에 전달됩니다. 내장 타입은 포맷 미니 언어를 C로 구현합니다. 사용자 정의 클래스는 임의의 명세 문자열을 받아들이도록 __format__을 정의할 수 있습니다. !r은 포매팅 전에 repr()을 호출합니다: f"{name!r}"은 끝에 공백이 있는 문자열을 따옴표로 묶인 repr로 변환하여, 보이지 않는 문자를 볼 수 있게 합니다. 변수 값이 이상해 보이고 그 안에 정확히 무엇이 있는지 확인해야 할 때마다 사용하세요.

사용자 입력 받기

input()은 프로그램을 일시 정지하고 사용자가 무언가 입력하기를 기다립니다. 사용자가 입력하고 Enter를 누른 내용이 반환값으로 돌아옵니다. 괄호 안의 문자열은 사용자에게 보이는 프롬프트입니다.

python
name = input("이름이 뭐예요? ")
print(f"안녕하세요, {name}님!")

input()은 사용자가 무엇을 입력하든 항상 문자열을 반환합니다. 42를 입력하면 숫자 42가 아닌 "42"가 돌아옵니다. 이걸로 산술을 하려면 명시적으로 변환해야 합니다:

python
age = int(input("나이가 몇 살이에요? "))
print(f"10년 후엔 {age + 10}살이 되겠네요.")

사용자가 변환할 수 없는 것을 입력하면 어떻게 될까요? 파이썬은 ValueError를 발생시킵니다. 이를 제대로 처리하는 방법은 파일과 예외 장에서 다룹니다.

input()은 프롬프트를 표준 출력에 쓰고, 표준 입력에서 한 줄을 읽고, 끝의 줄바꿈을 제거한 뒤 결과를 문자열로 반환합니다. 타입 추론은 없습니다. 터미널에서 오는 모든 것은 텍스트로 도착하며, 필요한 타입은 경계에서 명시적으로 변환하여 선언합니다.

python
name = input("이름이 뭐예요? ")
age  = int(input("나이가 몇 살이에요? "))

이 패턴(텍스트를 받고, 필요한 타입으로 변환)은 외부 데이터가 도착하는 모든 곳에 적용됩니다. int(), float(), str()이 변환 도구입니다. 문자열을 변환할 수 없으면 파이썬은 ValueError를 발생시키며, 파일과 예외 장에서 다룹니다.

input()은 얇은 인터페이스입니다: sys.stdout.write(prompt)를 호출하고, stdout을 flush한 다음, sys.stdin에서 한 줄을 읽고, 끝의 줄바꿈을 제거하고, 결과를 str로 반환합니다. 반환값은 항상 str로 설계되어 있습니다: 파이썬은 "42"가 정수, 부동소수점, 혹은 문자 그대로의 문자로 의도되었는지 추론할 방법이 없습니다. 경계에서의 타입 변환은 명시적입니다. 이는 파이썬 I/O의 근본적인 패턴입니다: 모든 외부 데이터는 텍스트로 도착하고, 코드는 진입점에서 타입을 선언합니다.

python
name  = input("이름을 입력하세요: ")
score = float(input("점수를 입력하세요 (0.0 ~ 1.0): "))

print(f"이름:  {name!r}")      # !r은 보이지 않는 공백을 드러냅니다
print(f"점수: {score:.1%}")

stderr에 쓰기

기본적으로 print()표준 출력에 씁니다: 터미널에 나타나고 파이프로 흘러들어가는 스트림입니다. 파이썬에는 표준 에러도 있는데, 진단과 경고를 위한 별도의 스트림입니다. 터미널에서는 똑같이 보이지만 서로 구분됩니다: 스크립트의 출력을 다른 명령으로 파이프할 때 stdout만 통과합니다. stderr는 항상 터미널에 도달합니다.

stderr에 쓰려면 print()file 인자를 사용합니다. 이는 sys를 import해야 하며, 모듈 장에서 다룹니다. 지금은 두 개의 스트림이 존재한다는 것과 왜 분리되어 있는지 아는 것으로 충분합니다.

실전 예제

사용자 입력으로 개인화되는 퀴즈:

python
name    = input("이름이 뭐예요? ")
subject = input("어떤 과목이요? ")

print(f"좋아요, {name}님. {subject} 퀴즈를 시작합니다.")
print("행운을 빌어요!")

두 입력 모두 문자열로 돌아와 f-string에 그대로 들어갑니다. 숫자가 아니라 텍스트로 사용하기 때문에 변환이 필요 없습니다.

정렬된 표 형식 출력을 사용하는 온도 변환기:

python
celsius    = float(input("섭씨 온도: "))
fahrenheit = celsius * 9 / 5 + 32

print(f"{'섭씨':>12} {'화씨':>12}")
print(f"{celsius:>12.1f} {fahrenheit:>12.1f}")

float()는 사용자로부터의 정수와 소수 둘 다 처리합니다. >12 명세는 숫자의 자릿수에 관계없이 열을 정렬된 상태로 유지합니다. 100-40을 입력해 보세요: 어느 쪽이든 출력은 깔끔하게 유지됩니다.

!r을 사용하여 파이썬이 받은 것을 정확히 드러내기, 출력이 이상해 보일 때 유용합니다:

python
name  = input("이름을 입력하세요: ")
score = float(input("점수를 입력하세요 (0.0 ~ 1.0): "))

print(f"이름:    {name!r}")
print(f"점수:    {score!r}")
print()
print(f"결과: {name}: {score:.1%}")

입력이 깔끔할 때는 {name}{name!r}이 동일하게 표시됩니다. 차이는 끝에 공백이 있거나 다른 보이지 않는 문자가 있을 때 나타납니다. 디버깅 중에 !r을 습관화하면 예상치 못한 값을 즉시 볼 수 있습니다.

파이썬에서 출력과 입력 연습하기Scrimba 강의에서 print, f-string, 사용자 입력에 대한 실습 연습을 진행하세요.Start the course →