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

输出和输入

从你写下第一行代码开始,你就会用到这两个工具:print() 在终端显示值,input() 从用户那里获取文本。它们很简单,但了解它们的行为可以让你在早期避免一些意外。

print()input() 是 Python 的标准终端 I/O 函数。两者都比表面看起来更具可配置性。print() 接受参数来控制值如何连接以及输出在哪里结束。input() 始终返回字符串,这决定了你如何处理每一个来自用户的值。

print() 封装了 sys.stdout;input() 封装了 sys.stdin。两者都只处理文本,将编码委托给流的编解码器,并默认缓冲输出。stdout 与 stderr 的分离,以及对刷新的控制,在实际程序中都很重要。

Python 如何运行你的代码

Python 从上到下逐行运行你的代码,严格按照你编写的顺序。不会跳来跳去。你写的顺序就是它们运行的顺序。永远如此。

python
city = "北京"
print(city)
print("Population: 14 million")

city 首先被赋值。第一个 print 运行。第二个 print 运行。每次都按这个顺序。

这很重要,因为你不能在赋值之前使用变量。Python 还没有见过它,会引发错误:

python
print(country)   # NameError: country is not defined yet
country = "中国"

随着你的程序越来越大,请记住这一点:你使用的任何东西都必须在使用之前定义。

Python 使用顺序执行:每个语句在遇到时被求值,通过文件一次自上而下的过程。它不会先预扫描整个文件。在赋值之前引用一个名称会在那一行(而不是更早)引发 NameError

python
city = "北京"
print(city)             # works: city is already bound
print(country)          # NameError: not yet assigned
country = "中国"

规则很简单:依赖项必须在使用它们的那一行之前定义。

Python 的执行模型是单遍顺序求值。名称解析发生在求值时,而不是解析时。解析器在不解析名称的情况下构建字节码,这就是为什么 NameError 是运行时异常而非语法错误。Python 没有变量提升(不像 JavaScript 的 var),也没有前向声明(不像 C)。一旦绑定,名称就可用;在此之前,任何引用都会引发异常。

python
print(country)   # NameError at runtime, not a syntax error
country = "中国"

打印输出

print() 是 Python 与你交流的方式。给它传递任何值,它就会显示该值。它会自动将你给它的任何东西转换为文本。

print() 通过 str() 将每个参数转换为字符串,用分隔符(默认是空格)连接它们,然后将结果加上换行符写入标准输出。理解默认值能让可选参数更容易理解。

print() 的完整签名是 print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)*objects 收集器接受任意数量的位置参数,并对每个参数调用 str()sepend 控制格式;file 将输出重定向到任何可写的流;flush 强制缓冲区立即清空。

python
print("Hello")    # Hello
print(42)         # 42
print(3.14)       # 3.14
print(True)       # True

多个值

你可以一次打印多个值,用逗号分隔。Python 默认在它们之间放一个空格。用 sep 修改分隔符:

多个位置参数分别通过 str() 转换,然后用 sep 连接。默认的 sep 是单个空格。覆盖它可以让你不用字符串拼接就能生成格式化输出:

每个位置参数在连接之前分别通过 str() 处理。连接使用 sep,然后追加 end,整个内容在对输出流的一次调用中写入。覆盖 sep 比手动构建字符串更整洁:

python
name = "小明"
age  = 28
print(name, age)                        # 小明 28
print("Name:", name)                    # Name: 小明
print("2024", "01", "15", sep="-")     # 2024-01-15
print("a", "b", "c", sep=", ")         # a, b, c

控制行尾

每次 print() 调用默认以换行符结尾,所以下一个输出从新行开始。用 end 来改变它。设置 end="" 会让下一次打印继续在同一行:

end 参数替换默认的换行符。将其设置为 "" 以抑制换行,设置为 " " 以在同一行加上空格,或设置为任何其他字符串。结合 sep,你可以生成大多数输出格式,无需手动构建字符串:

sepend 是仅关键字参数,默认值分别为 ' ''\n'。设置 end="" 是打印部分行并让下一次调用继续它的标准方式。对于实时输出,例如进度指示器或日志,flush=True 会强制缓冲区立即清空,而不是等待换行符或缓冲区填满。

python
print("Loading", end="")
print("...")
# Loading...

print("one", end=" | ")
print("two", end=" | ")
print("three")
# one | two | three

使用 f-strings 格式化输出

构建消息最简洁的方式是 f-strings。在开引号前加 f,然后用花括号包裹任何变量或表达式。Python 会在运行时填入。你可以在 {} 里放任何值、计算或方法调用。

f-strings 在运行时求值 {} 内的任何表达式,并将结果作为字符串嵌入。值后面的冒号引入格式规范:控制小数位数、对齐和数字格式的紧凑语法。它们比拼接更快、更易读,并且不需要显式的 str() 调用。

f-strings(PEP 498)将每个 {} 编译为调用 format(value, spec) 的字节码,后者委托给 value.__format__(spec)。任何实现 __format__ 的类都可以控制其在 f-string 中的显示。转换标志 !r!s!a 在格式调用之前应用 repr()str()ascii()!r 最有用:它在字符串周围显示引号,使不可见字符可见。

python
name  = "小明"
score = 980

# concatenation: clunky, requires str() for numbers
print("Player: " + name + ", Score: " + str(score))

# f-string: readable, no manual conversion
print(f"Player: {name}, Score: {score}")

你可以在 {} 内放任何表达式:算术、方法调用、格式规范:

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

print(f"Total: {total:.2f}")          # Total: 59.99
print(f"Name: {name.upper()}")        # Name: 小明
print(f"2 + 2 = {2 + 2}")             # 2 + 2 = 4

: 后面的格式规范控制值的显示方式:

python
ratio = 0.8765
count = 1234567
label = "revenue"

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

:.2f 意思是"两位小数"。你会经常将其用于价格和度量。其他的在你需要时再查。重点:{} 内可以放任何东西,不仅仅是变量名。

:.2f:.0% 涵盖了大多数格式化需求。带宽度的对齐指示符(><^)能生成整齐的表格输出。通用模式是 {value:[align][width][.precision][type]}。一旦你认出各个部分,任何规范都可以读懂,不必记住所有组合。

规范字符串被原样传递给 value.__format__(spec)。内置类型用 C 实现了格式迷你语言。自定义类可以定义 __format__ 以接受任意规范字符串。!r 在格式化之前调用 repr():f"{name!r}" 将带有尾随空白的字符串变成带引号的 repr,使不可见字符可见。每当变量的值看起来不对、需要确切看到其中有什么时,就使用它。

从用户获取输入

input() 会暂停你的程序,等待用户输入。无论他们输入什么(并按下 Enter)都会作为返回值返回。括号内的字符串是用户看到的提示。

python
name = input("What's your name? ")
print(f"Hello, {name}!")

input() 总是返回一个字符串,无论用户输入什么。输入 42,你得到的是 "42",而不是数字 42。要对其进行算术运算,需要显式转换:

python
age = int(input("How old are you? "))
print(f"In ten years you'll be {age + 10}.")

如果用户输入了无法转换的内容会怎样?Python 会引发 ValueError。如何正确处理这一点将在文件和异常章节中介绍。

input() 将提示写入标准输出,从标准输入读取一行,去掉尾随换行符,并将结果作为字符串返回。没有类型推断。来自终端的所有内容都以文本形式到达;你通过在边界处显式转换来声明你需要什么类型。

python
name = input("What's your name? ")
age  = int(input("How old are you? "))

这种模式(接收文本,转换为你需要的类型)适用于所有外部数据到达的地方。int()float()str() 是转换工具。如果字符串无法转换,Python 会引发 ValueError,这将在文件和异常章节中介绍。

input() 是一个薄接口:它调用 sys.stdout.write(prompt),刷新 stdout,从 sys.stdin 读取一行,去掉尾随换行符,并将结果作为 str 返回。返回值始终是 str,这是设计如此:Python 无法推断 "42" 是想表示整数、浮点数还是字面字符。边界处的类型转换是显式的。这是 Python I/O 的一个基本模式:所有外部数据都以文本形式到达,你的代码在入口点声明类型。

python
name  = input("Enter your name: ")
score = float(input("Enter your score (0.0 to 1.0): "))

print(f"Name:  {name!r}")      # !r reveals any invisible whitespace
print(f"Score: {score:.1%}")

写入 stderr

默认情况下,print() 写入标准输出:出现在终端中并流入管道的流。Python 还有标准错误,这是一个用于诊断和警告的独立流。它们在终端中看起来相同但是不同的:当你将脚本的输出通过管道传递给另一个命令时,只有 stdout 会通过。stderr 始终到达终端。

写入 stderr 使用 print()file 参数。这需要导入 sys,该内容将在模块章节中介绍。现在,知道这两个流存在以及它们为什么是分开的就够了。

实际应用

一个根据用户输入个性化的测验:

python
name    = input("What's your name? ")
subject = input("Which subject? ")

print(f"Okay, {name}. Starting your {subject} quiz.")
print("Good luck!")

两个输入都以字符串形式返回,直接进入 f-strings。不需要转换,因为你把它们当作文本使用,而不是数字。

一个带有对齐表格输出的温度转换器:

python
celsius    = float(input("Temperature in Celsius: "))
fahrenheit = celsius * 9 / 5 + 32

print(f"{'Celsius':>12} {'Fahrenheit':>12}")
print(f"{celsius:>12.1f} {fahrenheit:>12.1f}")

float() 可以处理用户输入的整数和小数。>12 规范使列保持对齐,无论数字有多少位。试试输入 100-40:输出都保持整齐。

使用 !r 显示 Python 实际接收到的内容,在输出看起来不对时很有用:

python
name  = input("Enter your name: ")
score = float(input("Enter your score (0.0 to 1.0): "))

print(f"Name:   {name!r}")
print(f"Score:  {score!r}")
print()
print(f"Result: {name}: {score:.1%}")

当输入干净时,{name}{name!r} 显示相同。当有尾随空格或其他不可见字符时,差异就出现了。在调试时养成使用 !r 的习惯,可以立即让意外的值变得可见。

练习 Python 中的输出和输入在 Scrimba 课程中通过实践练习学习 print、f-strings 和用户输入。Start the course →