1. Python输入输出基础概念
在Python编程中,输入输出(I/O)是与用户交互和数据处理的基础功能。Python提供了多种简单而强大的方式来处理输入输出操作,这些操作主要分为三类:标准输入输出、文件操作和数据序列化。
1.1 标准输入输出
标准输入输出是最基础的交互方式,主要通过控制台进行。Python使用内置函数input()获取用户输入,使用print()函数输出内容到控制台。
# 获取用户输入 user_input = input("请输入您的名字:") print("您好,", user_input)input()函数总是返回字符串类型,如果需要其他类型的数据,必须进行类型转换:
age = int(input("请输入您的年龄:")) print("明年您将", age + 1, "岁")1.2 文件操作基础
文件操作是更高级的I/O方式,Python通过open()函数创建文件对象,支持多种模式(读、写、追加等)。文件操作的基本流程是:打开文件→进行操作→关闭文件。
# 基本文件写入示例 with open('example.txt', 'w') as f: f.write("这是写入文件的内容")1.3 数据序列化
对于复杂数据结构,Python提供了pickle模块进行序列化和反序列化操作,可以将Python对象转换为字节流保存到文件,或从文件还原为对象。
import pickle data = {'name': '张三', 'age': 25, 'skills': ['Python', 'Java']} # 序列化到文件 with open('data.pkl', 'wb') as f: pickle.dump(data, f) # 从文件反序列化 with open('data.pkl', 'rb') as f: loaded_data = pickle.load(f)2. 格式化输出详解
Python提供了多种方式来格式化输出内容,使输出更加美观和易读。
2.1 使用str.format()方法
str.format()是Python推荐的字符串格式化方法,它通过位置参数或关键字参数来替换字符串中的占位符。
# 位置参数 print("{0}的年龄是{1}岁".format("李四", 30)) # 关键字参数 print("{name}的分数是{score}".format(name="王五", score=95)) # 混合使用 print("{0}的{subject}成绩是{score}".format("赵六", score=88, subject="数学"))格式说明符可以控制输出的对齐方式、宽度、精度等:
# 控制小数位数 pi = 3.1415926 print("PI的值是{0:.2f}".format(pi)) # 输出:PI的值是3.14 # 控制对齐和宽度 print("{:<10}".format("左对齐")) # 左对齐,宽度10 print("{:>10}".format("右对齐")) # 右对齐,宽度10 print("{:^10}".format("居中")) # 居中,宽度102.2 f-string格式化(Python 3.6+)
f-string是Python 3.6引入的字符串字面量格式化方法,语法更简洁,执行效率更高。
name = "张三" age = 25 print(f"{name}今年{age}岁") # 输出:张三今年25岁 # 支持表达式 a, b = 5, 10 print(f"{a} + {b} = {a + b}") # 输出:5 + 10 = 15 # 格式控制 pi = 3.1415926 print(f"PI的值是{pi:.2f}") # 输出:PI的值是3.142.3 旧式%格式化
虽然不推荐在新代码中使用,但许多旧代码仍使用%操作符进行格式化。
name = "李四" age = 30 print("%s今年%d岁" % (name, age)) # 输出:李四今年30岁 # 数字格式化 pi = 3.1415926 print("PI的值是%.2f" % pi) # 输出:PI的值是3.143. 文件操作深入
Python的文件操作功能强大,支持多种模式和操作方法。
3.1 文件打开模式详解
open()函数的mode参数决定了文件如何被打开:
| 模式 | 描述 |
|---|---|
| 'r' | 只读(默认) |
| 'w' | 写入,会覆盖已有文件 |
| 'x' | 独占创建,文件已存在则失败 |
| 'a' | 追加,写入内容添加到文件末尾 |
| 'b' | 二进制模式 |
| 't' | 文本模式(默认) |
| '+' | 更新(可读可写) |
常见组合:
- 'r+':读写,文件指针在开头
- 'w+':读写,会清空文件
- 'a+':读写,文件指针在末尾
3.2 文件读写方法
文件对象提供了多种读写方法:
# 写入文件 with open('example.txt', 'w') as f: f.write("第一行内容\n") f.write("第二行内容\n") # 读取整个文件 with open('example.txt', 'r') as f: content = f.read() print(content) # 逐行读取 with open('example.txt', 'r') as f: for line in f: print(line, end='') # 读取所有行到列表 with open('example.txt', 'r') as f: lines = f.readlines() print(lines) # ['第一行内容\n', '第二行内容\n']3.3 文件指针操作
文件指针表示当前读写位置,可以通过tell()获取位置,通过seek()移动指针。
with open('example.txt', 'rb+') as f: print(f.tell()) # 0,初始位置 f.write(b'0123456789') print(f.tell()) # 10,写入后位置 f.seek(5) # 移动到第6个字节 print(f.read(1)) # b'5' f.seek(-3, 2) # 从文件末尾前移3个字节 print(f.read(1)) # b'8'4. 高级输入输出技巧
4.1 上下文管理器与with语句
使用with语句可以确保文件正确关闭,即使发生异常也是如此。这是Python推荐的文件操作方式。
# 传统方式需要手动关闭文件 f = open('example.txt', 'w') try: f.write("一些内容") finally: f.close() # 使用with语句更简洁安全 with open('example.txt', 'w') as f: f.write("一些内容") # 文件会自动关闭4.2 标准输入输出重定向
Python可以通过修改sys.stdin、sys.stdout和sys.stderr来重定向标准输入输出。
import sys # 将输出重定向到文件 with open('output.txt', 'w') as f: sys.stdout = f print("这行内容会写入文件") sys.stdout = sys.__stdout__ # 恢复标准输出 print("这行内容会显示在控制台")4.3 使用pickle进行对象序列化
pickle模块可以序列化几乎所有的Python对象,包括自定义类的实例。
import pickle class Person: def __init__(self, name, age): self.name = name self.age = age p = Person("张三", 30) # 序列化到文件 with open('person.pkl', 'wb') as f: pickle.dump(p, f) # 从文件反序列化 with open('person.pkl', 'rb') as f: loaded_p = pickle.load(f) print(loaded_p.name, loaded_p.age) # 张三 304.4 JSON序列化
对于需要与其他语言交互的情况,JSON是更好的选择,Python提供了json模块。
import json data = { "name": "李四", "age": 25, "married": False, "hobbies": ["阅读", "游泳"] } # 序列化为JSON字符串 json_str = json.dumps(data, ensure_ascii=False, indent=2) print(json_str) # 写入JSON文件 with open('data.json', 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) # 从JSON文件读取 with open('data.json', 'r', encoding='utf-8') as f: loaded_data = json.load(f) print(loaded_data)5. 实际应用案例
5.1 日志记录系统
结合文件操作和时间模块,可以创建简单的日志系统。
import datetime def write_log(message, log_file='app.log'): timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') with open(log_file, 'a') as f: f.write(f"[{timestamp}] {message}\n") write_log("程序启动") write_log("用户登录") write_log("数据处理完成")5.2 配置文件读写
使用JSON格式存储和读取程序配置。
import json import os def load_config(config_file='config.json'): if not os.path.exists(config_file): # 默认配置 default_config = { "language": "zh-CN", "theme": "light", "font_size": 12 } with open(config_file, 'w') as f: json.dump(default_config, f, indent=2) return default_config with open(config_file, 'r') as f: return json.load(f) def save_config(config, config_file='config.json'): with open(config_file, 'w') as f: json.dump(config, f, indent=2) # 使用示例 config = load_config() print("当前语言:", config['language']) config['theme'] = 'dark' save_config(config)5.3 数据备份与恢复
使用pickle实现应用程序数据的备份和恢复功能。
import pickle import os from datetime import datetime class DataManager: def __init__(self, data_file='data.pkl'): self.data_file = data_file self.data = self.load_data() def load_data(self): if os.path.exists(self.data_file): with open(self.data_file, 'rb') as f: return pickle.load(f) return {} def save_data(self): with open(self.data_file, 'wb') as f: pickle.dump(self.data, f) def create_backup(self): timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') backup_file = f"backup_{timestamp}.pkl" with open(backup_file, 'wb') as f: pickle.dump(self.data, f) return backup_file def restore_from_backup(self, backup_file): with open(backup_file, 'rb') as f: self.data = pickle.load(f) self.save_data() # 使用示例 manager = DataManager() manager.data['users'] = ['张三', '李四'] manager.save_data() backup_file = manager.create_backup() print(f"创建备份: {backup_file}") # 模拟数据损坏 manager.data = {} manager.save_data() # 从备份恢复 manager.restore_from_backup(backup_file) print("恢复后的数据:", manager.data)6. 性能优化与注意事项
6.1 文件操作性能优化
处理大文件时,避免一次性读取全部内容,应使用逐行或分块读取。
# 不推荐 - 一次性读取大文件 with open('large_file.txt', 'r') as f: content = f.read() # 可能消耗大量内存 process(content) # 推荐 - 逐行处理 with open('large_file.txt', 'r') as f: for line in f: process(line) # 推荐 - 分块处理 chunk_size = 1024 * 1024 # 1MB with open('very_large_file.bin', 'rb') as f: while True: chunk = f.read(chunk_size) if not chunk: break process(chunk)6.2 异常处理
文件操作可能引发多种异常,如文件不存在、权限不足等,应妥善处理。
try: with open('important.txt', 'r') as f: content = f.read() except FileNotFoundError: print("文件不存在") except PermissionError: print("没有权限访问文件") except IOError as e: print(f"IO错误: {e}") except Exception as e: print(f"未知错误: {e}")6.3 编码问题
处理文本文件时,明确指定编码可以避免很多问题,推荐使用UTF-8。
# 明确指定编码 with open('multilingual.txt', 'w', encoding='utf-8') as f: f.write("中文 Español Français") with open('multilingual.txt', 'r', encoding='utf-8') as f: print(f.read())6.4 临时文件处理
tempfile模块可以安全地创建临时文件和目录。
import tempfile # 创建临时文件 with tempfile.NamedTemporaryFile(mode='w+', suffix='.tmp', delete=False) as tmp: print(f"临时文件路径: {tmp.name}") tmp.write("临时内容") tmp.seek(0) print(tmp.read()) # 临时文件会在with块结束后自动删除(除非设置delete=False)7. 调试与问题排查
7.1 常见问题与解决方案
问题1:文件写入后内容为空
可能原因:
- 文件以'w'模式打开后未写入内容
- 写入后未调用flush()或close()
- 文件指针位置不正确
解决方案:
# 确保写入后关闭文件或使用with语句 with open('output.txt', 'w') as f: f.write("实际内容") # 或者显式调用flush() f = open('output.txt', 'w') f.write("实际内容") f.flush() # 确保内容写入磁盘 f.close()问题2:读取文件时编码错误
可能原因:
- 文件编码与指定的编码不匹配
- 文件包含非法字符
解决方案:
# 尝试不同编码 encodings = ['utf-8', 'gbk', 'latin-1'] for enc in encodings: try: with open('problematic.txt', 'r', encoding=enc) as f: print(f.read()) break except UnicodeDecodeError: continue问题3:pickle加载时出现AttributeError
可能原因:
- 序列化和反序列化的环境不同(类定义不一致)
- 使用了不同Python版本
解决方案:
- 确保类定义在反序列化环境中可用
- 对于长期存储,考虑使用JSON等更稳定的格式
7.2 调试技巧
使用repr()显示原始内容
当输出内容显示不正常时,使用repr()可以显示原始形式,包括特殊字符。
with open('weird.txt', 'r') as f: content = f.read() print("正常显示:", content) print("原始形式:", repr(content))检查文件指针位置
文件操作不符合预期时,检查指针位置可以发现问题。
with open('example.txt', 'r+') as f: print("初始位置:", f.tell()) line = f.readline() print("读取一行后位置:", f.tell()) f.seek(0, 2) # 移动到文件末尾 print("移动到末尾后位置:", f.tell())使用try-except捕获特定异常
精确捕获异常可以提供更有用的调试信息。
try: with open('missing.txt', 'r') as f: content = f.read() except FileNotFoundError as e: print(f"调试信息: 文件路径 - {e.filename}, 错误 - {e.strerror}") # 可以在这里添加恢复逻辑或记录日志