Skip to content

04-输入与输出

本章代码基于 Python 3.11+ 编写

输入输出是程序与用户交互的基本方式,掌握 I/O 让程序能够接收数据并展示结果。


本章讲解 print() 输出函数、input() 输入函数、字符串格式化以及文件读写的基础知识。


概念铺垫

为什么需要输入输出?一个真实的交互场景

问题场景: 你在开发一个用户登录程序,需要获取用户输入的用户名和密码,并显示登录结果。

没有输入输出的困惑:

  • 如何让程序接收用户输入的信息?
  • 如何将处理结果展示给用户?
  • 如何控制输出的格式让信息更清晰?

使用输入输出的解决方案:

python
# 获取用户输入
username: str = input("请输入用户名:")
password: str = input("请输入密码:")

# 处理并输出结果
if username == "admin" and password == "123456":
    print(f"欢迎,{username}!登录成功。")
else:
    print("用户名或密码错误,登录失败。")

这就是输入输出的价值:让程序能够与人交流


输入输出解决了什么问题?

输入输出的本质是:程序与外部世界交换数据的通道

就像你用眼睛看(输入)、用嘴巴说(输出),程序也需要"看"和"说"。

输入输出的类型:

  1. 控制台 I/O:通过终端接收键盘输入和显示文本输出
  2. 文件 I/O:从文件读取数据和将数据写入文件
  3. 网络 I/O:通过网络接收和发送数据(后续章节讲解)

输出的最简用法

最常用的输出函数只有 print()

python
# 输出文本
print("Hello, Python!")

# 输出变量
name: str = "张三"
print(name)

# 输出多个值
age: int = 18
print("姓名:", name, "年龄:", age)

# 格式化输出
print(f"姓名:{name},年龄:{age}")

这就是输出的基本用法。接下来我们详细学习各类输出方式。


L1 理解层:会用

基本语法

┌─────────────────────────────────────────────────────────────┐
│                    print() 函数语法                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  print(value, ..., sep=' ', end='\n', file=sys.stdout,      │
│        flush=False)                                         │
│                                                             │
│  参数说明:                                                  │
│  • value     要输出的值(可以多个,用逗号分隔)               │
│  • sep       多个值之间的分隔符(默认空格)                   │
│  • end       输出结尾(默认换行符 \n)                       │
│  • file      输出目标(默认标准输出/屏幕)                   │
│  • flush     是否立即刷新缓冲区(默认 False)                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

最简示例

python
print("Hello, World!")  # 输出:Hello, World!

控制输出格式

sep 参数:自定义分隔符

┌─────────────────────────────────────────────────────────────┐
│                  sep 参数效果                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  print("A", "B", "C")           → A B C    (默认空格)     │
│  print("A", "B", "C", sep="")   → ABC     (无分隔)       │
│  print("A", "B", "C", sep="-")  → A-B-C  (自定义分隔符)  │
│  print("A", "B", "C", sep=", ") → A, B, C (逗号+空格)    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

示例

python
# 默认分隔符(空格)
print("姓名", "年龄", "城市")  # 姓名 年龄 城市

# 使用制表符分隔
print("姓名", "年龄", "城市", sep="\t")  # 姓名	年龄	城市

# 使用自定义分隔符
print("2024", "01", "15", sep="-")  # 2024-01-15
print("user", "example.com", sep="@")  # user@example.com

end 参数:控制行尾

┌─────────────────────────────────────────────────────────────┐
│                  end 参数效果                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  print("Hello")                → Hello\n    (默认换行)    │
│  print("Hello", end="")        → Hello      (不换行)      │
│  print("Hello", end=" ")       → Hello      (空格结尾)    │
│  print("Hello", end="---")     → Hello---   (自定义结尾)  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

示例

python
# 默认:每次输出后换行
print("第一行")
print("第二行")
# 输出:
# 第一行
# 第二行

# 不换行输出
print("第一行", end=" ")
print("第二行")
# 输出:第一行 第二行

# 进度条效果
import time

for i in range(5):
    print(f"加载 {i*20}%", end="\r")
    time.sleep(0.5)
print("\n加载完成!")

file 参数:输出到文件

python
# 输出到文件
with open("output.txt", "w", encoding="utf-8") as f:
    print("这是写入文件的内容", file=f)

# 输出到标准错误
import sys
print("错误信息", file=sys.stderr)

字符串格式化(核心)

Python 提供多种字符串格式化方式,推荐掌握 f-string(最现代、最简洁)。

┌─────────────────────────────────────────────────────────────┐
│              Python 字符串格式化方式对比                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  方式              版本要求      推荐度    示例              │
│  ──────────────────────────────────────────────────────     │
│  % 格式化           所有版本       ⭐       "Hi %s" % name   │
│  str.format()      Python 2.6+    ⭐⭐     "Hi {}".format()  │
│  f-string          Python 3.6+    ⭐⭐⭐⭐   f"Hi {name}"     │
│                                                             │
│  ⭐ 推荐:使用 f-string(Python 3.6+)                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

方式一:f-string(推荐)

f-string: 在字符串前加 f,用 {} 嵌入变量或表达式。

f-string 结构:
┌─────────────────────────────────────────────────────────────┐
│  f"文本 {变量} 文本 {表达式} 文本"                            │
│    │      │        │      │                                  │
│    │      │        │      └─ 可以是任意表达式                 │
│    │      │        └─ 嵌入代码的位置                          │
│    │      └─ 变量名或表达式                                   │
│    └─ f 或 F 前缀(必须)                                    │
│                                                             │
│  示例:                                                      │
│  name = "张三"                                               │
│  age = 18                                                    │
│  f"姓名:{name},年龄:{age}"                                │
│  → "姓名:张三,年龄:18"                                    │
│                                                             │
│  f"明年年龄:{age + 1}"                                      │
│  → "明年年龄:19"                                            │
└─────────────────────────────────────────────────────────────┘

最简示例

python
name: str = "张三"
age: int = 18

print(f"姓名:{name},年龄:{age}")
# 输出:姓名:张三,年龄:18

关键代码解释

代码含义结果
f"姓名:{name}"嵌入变量"姓名:张三"
f"明年:{age + 1}"嵌入表达式"明年:19"
f"大写:{name.upper()}"调用方法"大写:张三"

详细示例

python
name: str = "张三"
score: float = 85.5

# 嵌入变量
print(f"你好,{name}!")

# 嵌入表达式
print(f"你的分数是:{score}")
print(f"分数加倍:{score * 2}")

# 调用方法
print(f"名字大写:{name.upper()}")

# 多行 f-string
message: str = f"""
=== 学生信息 ===
姓名:{name}
分数:{score}
状态:{'通过' if score >= 60 else '未通过'}
"""
print(message)

格式化数值

┌─────────────────────────────────────────────────────────────┐
│              f-string 数值格式化格式                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  格式              含义              示例                    │
│  ──────────────────────────────────────────────────────     │
│  {value:.2f}     保留 2 位小数       3.14159 → 3.14         │
│  {value:.0f}     整数形式            3.14 → 3               │
│  {value:,.2f}    千位分隔符          1234567.89 →           │
│                                    1,234,567.89             │
│  {value:.2%}     百分比              0.856 → 85.60%         │
│  {value:.2e}     科学计数法          12345 → 1.23e+04       │
│  {value:<10}     左对齐,宽 10 位    'Python' → 'Python    '│
│  {value:>10}     右对齐,宽 10 位    'Python' → '    Python'│
│  {value:^10}     居中,宽 10 位      'Python' → '  Python  '│
│  {value:0>5}     右对齐,0 填充      42 → 00042             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

示例

python
price: float = 1234.567
discount: float = 0.85
population: int = 1400000000

# 小数位数
print(f"价格:{price:.2f}")  # 价格:1234.57

# 百分比
print(f"折扣:{discount:.1%}")  # 折扣:85.0%

# 千位分隔符
print(f"人口:{population:,}")  # 人口:1,400,000,000

# 对齐输出
print(f"{'商品':<10} | {'价格':>8}")
print(f"{'Python教程':<10} | {59.9:>8.2f}")
print(f"{'键盘':<10} | {199.0:>8.2f}")

# 补零
for i in range(1, 6):
    print(f"第 {i:02d} 题")
# 输出:第 01 题, 第 02 题, ...

方式二:str.format()

str.format(): 使用 {} 占位,通过 .format() 方法填充。

python
name: str = "张三"
age: int = 18

# 基本用法
print("姓名:{},年龄:{}".format(name, age))

# 索引占位
print("姓名:{0},年龄:{1}".format(name, age))
print("年龄:{1},姓名:{0}".format(name, age))  # 交换顺序

# 命名占位
print("姓名:{n},年龄:{a}".format(n=name, a=age))

# 格式化数值
print("价格:{:.2f}".format(3.14159))

方式三:% 格式化(旧式)

% 格式化: 类似 C 语言的 printf 风格。

python
name: str = "张三"
age: int = 18
score: float = 85.5

# 基本用法
print("姓名:%s,年龄:%d" % (name, age))

# 格式化数值
print("分数:%.1f" % score)  # 分数:85.5

# 常见占位符
print("字符串:%s" % "Hello")   # %s 字符串
print("整数:%d" % 42)          # %d 整数
print("浮点数:%.2f" % 3.14)   # %f 浮点数

提示: % 格式化是旧式语法,新项目推荐使用 f-string。


input() 函数详解

基本语法

┌─────────────────────────────────────────────────────────────┐
│                    input() 函数语法                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  input(prompt=None)                                         │
│                                                             │
│  参数说明:                                                  │
│  • prompt    提示文本(可选,显示在输入前)                   │
│                                                             │
│  返回值:                                                    │
│  • 始终返回字符串类型(str)                                 │
│                                                             │
│  执行流程:                                                  │
│  1. 显示提示文本(如果有)                                   │
│  2. 等待用户输入                                             │
│  3. 用户按回车键                                             │
│  4. 返回输入的文本                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

最简示例

python
# 基本输入
name: str = input("请输入你的名字:")
print(f"你好,{name}!")

关键代码解释

代码含义结果
input()等待用户输入返回输入的字符串
input("提示:")显示提示后等待返回输入的字符串
int(input())输入转整数将字符串转为整数

详细示例

python
# 获取用户信息
name: str = input("请输入姓名:")
age_str: str = input("请输入年龄:")

# 类型转换(input 返回的总是字符串)
age: int = int(age_str)

print(f"{name},明年你 {age + 1} 岁")

输入类型转换

┌─────────────────────────────────────────────────────────────┐
│              输入类型转换注意事项                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ⚠️ 重要:input() 始终返回字符串!                           │
│                                                             │
│  需要其他类型时,必须手动转换:                               │
│                                                             │
│  int(input())     → 转换为整数                              │
│  float(input())   → 转换为浮点数                            │
│  bool(input())    → ⚠️ 陷阱!非空字符串都是 True            │
│                                                             │
│  ❌ 错误:                                                  │
│  age = input("年龄:")  # age 是字符串 "18"                   │
│  print(age + 1)       # TypeError!                         │
│                                                             │
│  ✅ 正确:                                                  │
│  age = int(input("年龄:"))  # age 是整数 18                 │
│  print(age + 1)            # 19                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

示例

python
# 整数输入
age: int = int(input("请输入年龄:"))

# 浮点数输入
height: float = float(input("请输入身高(米):"))

# 多个输入(空格分隔)
data: str = input("输入两个数字(空格分隔):")
parts: list[str] = data.split()
x: float = float(parts[0])
y: float = float(parts[1])
print(f"和:{x + y}")

安全的输入处理

处理无效输入

python
# ❌ 不安全的做法:直接转换,可能崩溃
age: int = int(input("请输入年龄:"))  # 输入 "abc" 会报错!

# ✅ 安全的做法:使用 try-except
while True:
    try:
        age: int = int(input("请输入年龄:"))
        break
    except ValueError:
        print("输入无效,请输入一个整数!")

print(f"你的年龄是:{age}")

输入验证函数

python
def get_int(prompt: str, min_val: int | None = None, max_val: int | None = None) -> int:
    """
    获取用户输入的整数,可选范围验证
    
    Args:
        prompt: 提示文本
        min_val: 最小值(可选)
        max_val: 最大值(可选)
    
    Returns:
        有效的整数输入
    """
    while True:
        try:
            value: int = int(input(prompt))
            
            if min_val is not None and value < min_val:
                print(f"输入不能小于 {min_val}")
                continue
            
            if max_val is not None and value > max_val:
                print(f"输入不能大于 {max_val}")
                continue
            
            return value
        except ValueError:
            print("请输入有效的整数!")

# 使用示例
age: int = get_int("请输入年龄(0-150):", min_val=0, max_val=150)
print(f"年龄验证通过:{age}")

从简单到复杂:输入输出的渐进应用

层级1:基础输出

python
# 简单输出
print("Hello, Python!")

# 输出变量
message: str = "欢迎学习 Python"
print(message)

层级2:格式化输出

python
# f-string 格式化
name: str = "张三"
score: float = 95.5

print(f"学生:{name},分数:{score:.1f}")

层级3:基础输入

python
# 获取输入并处理
user_name: str = input("请输入用户名:")
print(f"欢迎,{user_name}!")

层级4:输入类型转换

python
# 输入数字并计算
num1: float = float(input("输入第一个数:"))
num2: float = float(input("输入第二个数:"))
print(f"和:{num1 + num2}")
print(f"积:{num1 * num2}")

层级5:安全输入与格式化表格

python
# 安全的输入 + 格式化输出表格
def get_student_info() -> dict[str, str | float]:
    """获取学生信息"""
    while True:
        try:
            name: str = input("姓名:")
            if not name.strip():
                print("姓名不能为空")
                continue
            
            score: float = float(input("分数:"))
            if not 0 <= score <= 100:
                print("分数必须在 0-100 之间")
                continue
            
            return {"name": name, "score": score}
        except ValueError:
            print("请输入有效数字!")

# 收集数据
students: list[dict[str, str | float]] = []
for _ in range(2):
    students.append(get_student_info())

# 格式化输出表格
print(f"\n{'姓名':<10} | {'分数':>6} | {'等级':>4}")
print("-" * 26)
for s in students:
    score: float = float(s["score"])
    grade: str = "优秀" if score >= 90 else "良好" if score >= 70 else "及格" if score >= 60 else "不及格"
    print(f"{s['name']:<10} | {score:>6.1f} | {grade:>4}")

关键代码解释:

代码含义为什么这样写
while True: try: ... except ValueError:无限循环+异常捕获:持续要求输入直到合法用户输错不崩溃,捕获后提示重新输入
if not name.strip():判断去除空白后是否为空字符串防止用户只按空格通过验证
if not 0 <= score <= 100:Python 链式比较:等价于 0 <= score and score <= 100范围验证,比写两个条件更简洁
for _ in range(2):循环 2 次,_ 表示不使用循环变量约定俗成:_ 表示该变量值不重要
f"{'姓名':<10}"字符串左对齐,总宽度 10固定列宽使表格整齐对齐
"优秀" if score >= 90 else "良好" if score >= 70 else ...链式嵌套三元表达式:多档判断简洁写法,注意从高分到低分依次判断

综合应用:简易计算器

这个示例综合运用输入输出:

python
# 简易计算器(Python 3.11+)

def main() -> None:
    """简易计算器主程序"""
    print("=== 简易计算器 ===")
    print("支持运算:+ - * /")
    print("输入 'q' 退出程序\n")
    
    while True:
        # 获取输入
        user_input: str = input("\n请输入算式(如 3 + 5):").strip()
        
        # 退出检查
        if user_input.lower() == 'q':
            print("感谢使用,再见!")
            break
        
        # 解析算式
        try:
            parts: list[str] = user_input.split()
            if len(parts) != 3:
                print("格式错误!请按 '数字 运算符 数字' 格式输入")
                continue
            
            num1: float = float(parts[0])
            operator: str = parts[1]
            num2: float = float(parts[2])
            
            # 计算结果
            if operator == '+':
                result: float = num1 + num2
            elif operator == '-':
                result = num1 - num2
            elif operator == '*':
                result = num1 * num2
            elif operator == '/':
                if num2 == 0:
                    print("错误:除数不能为零!")
                    continue
                result = num1 / num2
            else:
                print(f"错误:不支持的运算符 '{operator}'")
                continue
            
            # 输出结果
            print(f"结果:{num1:g} {operator} {num2:g} = {result:g}")
            
        except ValueError:
            print("错误:请输入有效的数字!")

if __name__ == "__main__":
    main()

这个程序展示了:

  • print() 输出提示和结果
  • input() 获取用户输入
  • 字符串解析和类型转换
  • 错误处理和输入验证
  • f-string 格式化输出
  • 循环交互设计

关键代码说明:

代码含义为什么这样写
input(...).strip()获取输入并去除两端空白用户可能误输入前后空格,strip 防止解析出错
user_input.split()按空白字符分割成列表"3 + 5" 拆为 ["3", "+", "5"] 三部分
float(parts[0])将字符串转为浮点数input 返回字符串,必须转换才能计算
except ValueError:捕获类型转换失败异常用户输入非数字(如 "abc")时 float() 抛出此异常
continue跳过本次循环,回到 while 起点出错后不中断程序,让用户重新输入
{num1:g}格式化数字,去除多余的零3.0 显示为 33.50 显示为 3.5,更整洁

文件读写基础

写入文件

python
# 方式1:使用 print 写入
with open("hello.txt", "w", encoding="utf-8") as f:
    print("Hello, File!", file=f)

# 方式2:使用 write 方法
with open("hello.txt", "w", encoding="utf-8") as f:
    f.write("Hello, File!\n")
    f.write("第二行内容\n")

读取文件

python
# 读取全部内容
with open("hello.txt", "r", encoding="utf-8") as f:
    content: str = f.read()
    print(content)

# 逐行读取
with open("hello.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line.strip())  # strip() 去除行尾换行符

# 读取所有行到列表
with open("hello.txt", "r", encoding="utf-8") as f:
    lines: list[str] = f.readlines()
    print(lines)

文件模式

┌─────────────────────────────────────────────────────────────┐
│                  文件打开模式                                │
├──────────┬──────────────────────────────────────────────────┤
│  模式    │          说明                                    │
├──────────┼──────────────────────────────────────────────────┤
│  "r"     │ 只读(默认),文件不存在会报错                   │
│  "w"     │ 只写,覆盖原内容,文件不存在会创建               │
│  "a"     │ 追加,在文件末尾添加,文件不存在会创建           │
│  "x"     │ 独占创建,文件已存在会报错                       │
│  "rb"    │ 二进制只读                                       │
│  "wb"    │ 二进制只写                                       │
└──────────┴──────────────────────────────────────────────────┘

L2 实践层:用好

推荐做法

做法原因示例
新项目统一用 f-string最简洁、最快速、最易读f"姓名:{name}"
文件操作用 with open()自动关闭文件,防资源泄漏with open("a.txt") as f:
输入后立即做类型转换避免字符串运算错误int(input("年龄:"))
try-except 包裹输入转换防止无效输入导致崩溃try: int(input()) except ValueError:
大数据用逐行读取避免一次性加载到内存for line in f:
输出重定向用 file= 参数灵活切换输出目标print(err, file=sys.stderr)
进度条用 end="\r" 覆盖原地刷新,视觉友好print(f"{p}%", end="\r")
表格输出用 :<n / :>n 对齐固定列宽,格式整齐f"{'名称':<10} {价格:>8}"

反模式:不要这样做

python
# ❌ 错误:新项目使用 % 格式化
print("姓名:%s,年龄:%d" % (name, age))

# ✅ 正确:使用 f-string
print(f"姓名:{name},年龄:{age}")
python
# ❌ 错误:不处理无效输入
age: int = int(input("年龄:"))  # 输入 "abc" 崩溃

# ✅ 正确:用 try-except 安全处理
while True:
    try:
        age: int = int(input("年龄:"))
        break
    except ValueError:
        print("请输入整数!")
python
# ❌ 错误:忘记关闭文件(资源泄漏)
f = open("data.txt", "r")
content = f.read()
# f.close()  # 忘记关闭!

# ✅ 正确:使用 with 自动管理
with open("data.txt", "r") as f:
    content = f.read()
python
# ❌ 错误:用 f-string 输出大量调试信息却没有格式控制
data = {"key1": "val1", "key2": "val2"}  # 复杂对象
print(f"数据:{data}")  # 可能难以阅读

# ✅ 正确:用 pprint 或 json 美化输出
import json
print(json.dumps(data, indent=2, ensure_ascii=False))
python
# ❌ 错误:一次性读取大文件
with open("large.log") as f:
    lines = f.readlines()  # 10GB 文件直接崩溃

# ✅ 正确:逐行读取
with open("large.log") as f:
    for line in f:
        process(line)

常见陷阱

陷阱说明解决方案
bool(input()) 总是 True非空字符串都是 Trueinput().lower() in ("yes", "y")
\r 不刷新end="\r" 后内容不立即显示flush=True
print() 换行不当end="" 缺乏换行导致输出粘连适时补充 print() 换行
文件编码问题Windows 默认 GBK,不是 UTF-8始终指定 encoding="utf-8"
input() 阻塞等待用户输入时程序卡住考虑超时或异步方案(进阶)
f-string 中的引号冲突f"name is {d["key"]}" 语法错误用不同引号:f"name is {d['key']}"

适用场景

场景是否推荐原因
简单输出✅ print()最基础的输出方式
变量/表达式嵌入✅ f-string现代语法,最简洁
复杂模板(邮件、报告)❓ str.format() 或模板引擎f-string 适合短文本
多语言/国际化❓ 模板引擎(Jinja2 等)f-string 不便于翻译管理
调试输出✅ print() + f-string快速调试
生产日志❌ 不推荐 print()用 logging 模块(后续章节)
大文件处理✅ 逐行迭代内存友好
配置文件读写✅ json/toml 模块结构化数据优于纯文本
敏感信息输入❌ input() 不够用 getpass.getpass() 隐藏输入

本章小结

┌─────────────────────────────────────────────────────────────┐
│                  输入与输出 知识要点                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   print() 输出:                                             │
│   ✓ 基本用法:print(value)                                  │
│   ✓ sep 参数:控制分隔符(默认空格)                        │
│   ✓ end 参数:控制行尾(默认换行)                          │
│   ✓ file 参数:输出到文件                                   │
│                                                             │
│   字符串格式化:                                             │
│   ✓ f-string(推荐):f"文本 {变量}"                       │
│   ✓ 数值格式:{value:.2f} {value:,} {value:.1%}            │
│   ✓ 对齐:{value:<10} {value:>10} {value:^10}             │
│                                                             │
│   input() 输入:                                             │
│   ✓ 始终返回字符串                                          │
│   ✓ 需要其他类型时手动转换                                  │
│   ✓ 使用 try-except 处理无效输入                            │
│                                                             │
│   文件读写:                                                 │
│   ✓ 使用 with open() 自动管理文件                           │
│   ✓ 模式:r(读)、w(写)、a(追加)                      │
│   ✓ read() 读全部、readlines() 读行列表                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘