Python入门到精通(三):模块、I/O、文件处理

部署运行你感兴趣的模型镜像

关注我不迷路,您的点赞+收藏,就是我坚持的动力!

引言

在Python编程中,模块和输入输出(I/O)操作是我们每天都要打交道的重要内容。
今天,我们将深入探讨如何优雅地处理文件、数据格式和异常,让你的代码更加健壮和专业!

一、模块:Python的"乐高积木"

模块就是一个Python文件(.py),包含函数、类和变量,可以被其他Python程序导入使用。模块是基本的组织单位,让我们可以把相关功能组织在一起。模块化后,代码逻辑可以重复利用,避免命名冲突,模块内代码清晰容易维护

模块通常使用import语句来导入模块。
常见标准库模块包括:

# 常见模块
math:提供了数学函数,如三角函数、对数、幂等。
random:用于生成随机数,包括随机选择、打乱序列等。
datetime:处理日期和时间的模块。
os:提供了与操作系统交互的功能,如文件操作、目录操作等。
sys:提供了与Python解释器交互的变量和函数。
json:用于处理JSON数据。
re:正则表达式模块,用于字符串匹配和替换。
collections:提供了额外的数据结构,如 defaultdict、Counter、deque等。
itertools:提供了用于操作迭代对象的函数。
time:提供了时间相关的函数,如 sleep、time 等。

常用第三方库包括

# 数据科学
pip install numpy pandas matplotlib scikit-learn
# numpy:科学计算库
# pandas:数据分析库
# matplotlib:绘图库
# scikit-learn:机器学习库

# 网络开发
pip install requests beautifulsoup4 flask django
# requests:HTTP库
# beautifulsoup4:解析HTML和XML文档的库
# flash:轻量级的Web应用框架
# django:高级的Web框架

# 自动化
pip install selenium opencv-python pygame
# selenium: 一个用于Web应用程序测试的工具
# opencv-python: OpenCV(的Python绑定,是一个开源的计算机视觉和机器学习软件库
# pygame: 一个用于编写视频游戏的Python模块

另:还可以自行编写一些通用化模块,供系统使用。

二、文件读写

Python中的文件读写是一个基础且重要的操作。
文件读写通常涉及打开文件、读取或写入数据、关闭文件等步骤。Python内置了open()函数用于打开文件,并返回一个文件对象。通过文件对象,我们可以调用各种方法来读写文件。

2.1 文件的基本操作

read(size): 读取指定大小的数据,如果不指定size,则读取整个文件。
readline(): 读取一行。
readlines(): 读取所有行并返回一个列表。
write(string): 写入字符串。
writelines(list): 写入一个字符串列表。
close(): 关闭文件。
# 示例
# 1. 打开文件
file = open("filename", "mode")
# 2. 读写操作
content = file.read()
# 3. 关闭文件
file.close()

# 文件的操作模式
模式		描述			文件不存在时			文件存在时			指针位置
'r'		只读(默认)		报错				正常打开				开头
'w'		写入			创建新文件			覆盖原内容			开头
'a'		追加			创建新文件			在末尾追加			末尾
'x'		独占创建		创建新文件			报错					开头
'r+'	读写			报错					正常打开				开头
'w+'	读写			创建新文件			覆盖原内容			开头
'a+'	读写			创建新文件			在末尾读写			末尾

2.2 with:上下文管理器

with语句是上下文管理器协议的一种应用,它用于简化资源管理,确保资源在使用后被正确释放。
上下文管理器是实现了__enter__和__exit__方法的对象。
当执行with语句时,会先调用__enter__方法,然后执行with语句块中的代码,最后无论是否发生异常,都会调用__exit__方法。
使用with语句的好处是,即使代码块中发生了异常,__exit__方法也会被调用,从而可以执行清理操作(比如关闭文件)。

# 传统方法
file = None
try:
    file = open("example.txt", "w", encoding="utf-8")
    file.write("Hello, World!\n")
    file.write("这是第二行\n")
except IOError as e:
    print(f"文件操作错误: {e}")
finally:
    if file:
        file.close()
            
# 自动管理资源,确保文件正确关闭
with open("example.txt", "a", encoding="utf-8") as f:
	f.write("这是追加的内容\n")
# 离开with块后文件自动关闭

 # 读写文件
with open("example.txt", "a+", encoding="utf-8") as f:
	f.write("这是追加的内容\n")
	# 重置文件指针
	f.seek(0)
	# 读取整个文件
	content = f.read()
	print("文件内容:")
	print(content)
	# 重置文件指针
	f.seek(0)
	# 逐行读取
	print("\n逐行读取:")
	for i, line in enumerate(f, 1):
	    print(f"第{i}行: {line.strip()}")

大文件处理技巧:
1)逐块读取
2)逐行读取

# 逐块读取
with open(input_file, "rb") as infile, open(output_file, "wb") as outfile:
   while True:
       chunk = infile.read(chunk_size)
       if not chunk: # 如果读取到的数据为空
           break
       # 处理数据块(这里只是简单复制)
       outfile.write(chunk)
# 逐行读取
line_count = 0
word_count = 0
with open(filepath, "r", encoding=encoding) as f:
    for line in f:
        line_count += 1
        word_count += len(line.split())
        # 每处理10000行输出一次进度
        if line_count % 10000 == 0:
            print(f"已处理 {line_count} 行,{word_count} 个单词")

三、输入输出

3.1 标准输入输出

标准输入使用input函数来读取用户输入

# 单个输入
name = input("请输入您的姓名:")
print(f"你好,{name}!")
# 多个输入
age = input("请输入您的年龄:")
city = input("请输入您的城市:")
print(f"信息:{name}, {age}岁, 来自{city}")
# 输入值类型转换
num1 = int(input("请输入第一个数字:"))
num2 = int(input("请输入第二个数字:"))
print(f"两个数字的和:{num1 + num2}")

标准输入使用print函数来进行输出

# 基本输出
print("Hello, World!")
# 输出多个值(默认用空格分隔)
print("Python", "Java", "C++")  # Python Java C++
# 修改分隔符
print("Python", "Java", "C++", sep=", ")  # Python, Java, C++
# 修改结束符(默认换行)
print("Hello", end=" ")  # 不换行,以空格结束
print("World")           # Hello World
# 格式化输出
name = "张三"
score = 95.5
print(f"学生:{name},分数:{score:.1f}")  # f-string
print("学生:{},分数:{:.1f}".format(name, score))  # format方法
print("学生:%s,分数:%.1f" % (name, score))  # %格式化
# 输出均为:学生:张三,分数:95.5

3.2 输入输出的高级用法

1)sys 模块

sys模块是Python标准库中的一个内置模块,它提供了与Python解释器及其环境(如命令行参数、标准输入输出、错误流、退出程序等)进行交互的变量和函数。

sys.stdin 读取输入
sys.stdout 输出显示

import sys
# 读取单行输入
data = sys.stdin.readline().strip()  # 读取一行,去除换行符
print(f"读取到:{data}")

# 读取所有输入(直到EOF)
print("请输入内容(Ctrl+D结束):")
all_input = sys.stdin.read()
print(f"读取的全部内容:\n{all_input}")

# 逐行读取
print("请输入多行内容(Ctrl+D结束):")
lines = sys.stdin.readlines()
print(f"共读取 {len(lines)} 行:")
for i, line in enumerate(lines, 1):
    print(f"第{i}行:{line.strip()}")

2)交互式输入

getpass:密码输入库

# 输入验证循环
while True:
    try:
        age = int(input("请输入年龄(0-120):"))
        if 0 <= age <= 120:
            break
        else:
            print("年龄必须在0-120之间!")
    except ValueError:
        print("请输入有效的数字!")
print(f"您的年龄是:{age}")
# 密码输入(隐藏输入内容)
import getpass
password = getpass.getpass("请输入密码:")
print(f"密码长度:{len(password)}")

3) 进度条显示

import sys
import time
# 简单进度条
def progress_bar(iteration, total, length=50):
    percent = 100 * (iteration / total)
    filled_length = int(length * iteration // total)
    bar = '█' * filled_length + '-' * (length - filled_length)
    sys.stdout.write(f'\r进度:|{bar}| {percent:.1f}% ') # 行首输出
    sys.stdout.flush() # 立即刷新缓冲区
# 使用示例
total_items = 100
for i in range(total_items + 1):
    time.sleep(0.05)  # 模拟工作
    progress_bar(i, total_items)
print()  # 换行

!! print() 会自动添加换行符,sys.stdout.write()不会,使用\n才能换行。

3.3 处理大文件和流

1)分块读取 和 逐行读取

import sys
# 分块读取大文件(避免内存不足)
chunk_size = 1024  # 1KB
total_bytes = 0
print("开始读取标准输入(Ctrl+D结束)...")
while True:
    chunk = sys.stdin.read(chunk_size)
    if not chunk: # 如果读取到的数据为空,代表到了文件尾端
        break
    total_bytes += len(chunk)
print(f"总共读取 {total_bytes} 字节")

# 逐行处理大文件
line_count = 0
for line in sys.stdin:
    line_count += 1
    # 处理每一行
    processed_line = line.strip().upper()
    sys.stdout.write(f"第{line_count}行:{processed_line}\n")
print(f"总共处理 {line_count} 行")

2)缓冲和非缓冲I/O

import sys
# 设置缓冲区大小
sys.stdout = open('buffered.txt', 'w', buffering=2048)  # 2KB缓冲区
# 无缓冲输出(立即写入)
sys.stderr = open('unbuffered.txt', 'w', buffering=0)
# 行缓冲(遇到换行符立即写入)
sys.stdout = open('linebuffered.txt', 'w', buffering=1)
# 手动刷新缓冲区
print("这条消息在缓冲区")
sys.stdout.flush()  # 立即写入
print("这条消息也会在缓冲区")

四、异常处理的最佳实践

4.1 基础异常处理Try-Except

def basic_exception_handling():
    # 1. 最基本的try-except
    try:
        result = 10 / 0
    except ZeroDivisionError as e:
        print(f"捕获到除零错误: {e}")
    # 2. 捕获多个异常
    try:
        num = int("abc")
        result = 10 / num
    except (ValueError, ZeroDivisionError) as e:
        print(f"捕获到数值错误: {e}")
    # 3. 分别处理不同异常
    try:
        file = open("nonexistent.txt", "r")
        content = file.read()
    except FileNotFoundError as e:
        print(f"文件未找到: {e}")
    except IOError as e:
        print(f"I/O错误: {e}")
    except Exception as e:
        print(f"其他错误: {e}")
    finally:
        print("无论是否发生异常,都会执行这里")
    # 4. 使用else子句
    try:
        data = {"key": "value"}
        value = data["key"]
    except KeyError as e:
        print(f"键不存在: {e}")
    else:
        print(f"操作成功,获取的值: {value}")
    finally:
        print("清理工作完成")

4.2 自定义异常

# 自定义异常类
# 验证错误
class ValidationError(Exception):
    def __init__(self, message, field=None, value=None):
        self.message = message
        self.field = field
        self.value = value
        super().__init__(self.message)
    def __str__(self):
        if self.field:
            return f"{self.message} (字段: {self.field}, 值: {self.value})"
        return self.message
# 数据库错误
class DatabaseError(Exception):
    def __init__(self, message, query=None, params=None):
        self.message = message
        self.query = query
        self.params = params
        super().__init__(self.message)
    def __str__(self):
        details = []
        if self.query:
            details.append(f"查询: {self.query}")
        if self.params:
            details.append(f"参数: {self.params}")
        if details:
            return f"{self.message} ({'; '.join(details)})"
        return self.message

# 使用自定义异常
# 验证用户数据
def validate_user_data(data):
    if "username" not in data:
        raise ValidationError("用户名不能为空", field="username")
    if len(data.get("username", "")) < 3:
        raise ValidationError("用户名至少3个字符", field="username", value=data.get("username"))
    if "email" not in data or "@" not in data["email"]:
        raise ValidationError("邮箱格式不正确", field="email", value=data.get("email"))
    return True

# 用户注册流程
def process_user_registration(user_data):
    try:
        validate_user_data(user_data)
        print("用户数据验证通过")
        # 模拟数据库操作
        raise DatabaseError("插入数据失败", query="INSERT INTO users", params=user_data)
    except ValidationError as e:
        print(f"数据验证失败: {e}")
        # 可以记录日志、返回错误信息等
        return {"success": False, "error": str(e)}
    except DatabaseError as e:
        print(f"数据库操作失败: {e}")
        return {"success": False, "error": "数据库错误"}
    except Exception as e:
        print(f"未知错误: {e}")
        return {"success": False, "error": "系统错误"}
    else:
        return {"success": True, "message": "注册成功"}
    finally:
        print("注册流程结束")
# 测试
test_data = {"username": "ab", "email": "invalid"}
result = process_user_registration(test_data)
print(f"结果: {result}")

五、高频面试题解析

问题1:with语句的工作原理是什么?

with语句的背后是上下文管理器协议,任何实现了__enter__和__exit__方法的对象都可以作为上下文管理器。
1)with语句确保资源被正确释放
2)enter返回的对象被as接收
3)exit在退出时调用,处理异常
4)内置的open()函数返回的文件对象就是上下文管理器

class MyContext:
    def __enter__(self):
        print("进入上下文")
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("退出上下文")
        if exc_type is not None:
            print(f"发生异常: {exc_val}")
        # 返回True表示异常已处理,不再向上抛出
        return False
    def do_something(self):
        print("执行操作")
# 使用
with MyContext() as ctx:
    ctx.do_something()
    # 这里如果发生异常,会在__exit__中处理

# 等同于:
ctx = MyContext()
ctx.__enter__()
try:
    ctx.do_something()
except Exception as e:
    ctx.__exit__(type(e), e, e.__traceback__)
    raise
else:
    ctx.__exit__(None, None, None)

问题2:Python中如何处理大文件,避免内存溢出?

1)文本文件使采用逐行读取:for line in file

with open("large_file.txt", "r", encoding="utf-8") as f:
    for line in f:  # 一次只读取一行到内存
        process_line(line)

2)二进制文件采用分块读取:用指定大小的chunk读取

chunk_size = 1024 * 1024  # 1MB
with open("large_file.bin", "rb") as f:
    while True:
        chunk = f.read(chunk_size)
        if not chunk:
            break
        process_chunk(chunk)

3)使用生成器处理:实现惰性加载

def read_large_file(filepath, chunk_size=1024):
    with open(filepath, "rb") as f:
        while True:
            data = f.read(chunk_size)
            if not data:
                break
            yield data

# 使用生成器
for chunk in read_large_file("large_file.bin"):
    process_chunk(chunk)

4)超大文件考虑使用mmap(内存映射文件)

import mmap
with open("large_file.bin", "r+b") as f:
    # 创建内存映射
    mm = mmap.mmap(f.fileno(), 0)
    # 像操作字节数组一样操作文件
    data = mm[1000:2000]  # 只读取指定范围
    mm.close()

问题3:Python中json.loads()和json.load()有什么区别?

loads字符串加载成对象类,load从文件中加载成对象类
dumps将字符串对象写入到文件中,dump将python对象写入文件中

1)loads/dumps:处理字符串
2)load/dump:处理文件对象
3)load和loads方法都有对应的参数控制编码、缩进等
4)设置ensure_ascii=False支持中文

import json
# json.loads() 从字符串加载 load string
json_string = '{"name": "张三", "age": 25}'
data_from_string = json.loads(json_string)
print(data_from_string)  # {'name': '张三', 'age': 25}
# json.load() 从文件对象加载
with open("data.json", "r", encoding="utf-8") as f:
    data_from_file = json.load(f)
    print(data_from_file)

# 对应的保存方法:
# json.dumps() 将对象转换为字符串
json_str = json.dumps({"name": "张三", "age": 25}, ensure_ascii=False)
print(json_str)  # {"name": "张三", "age": 25}
# json.dump() 将对象保存到文件
with open("output.json", "w", encoding="utf-8") as f:
    json.dump({"name": "张三", "age": 25}, f, ensure_ascii=False, indent=2)

六、总结与最佳实践

核心要点回顾

模块化开发:合理组织代码,提高复用性
文件操作:使用with语句确保资源正确释放
异常处理:精确捕获异常,提供有用的错误信息
输入输出:灵活处理各种I/O场景

最佳实践建议

✅ 推荐做法:
使用pathlib处理文件路径,更直观安全
处理大文件时,使用生成器或分块、分行读取
为自定义异常提供有用的错误信息
使用json.dump/load时指定ensure_ascii=False支持中文
❌ 避免做法:
不要用字符串拼接处理文件路径
不要一次性读取大文件到内存
不要忽略文件编码(默认使用utf-8)
不要在没有检查的情况下覆盖文件

相关实战小游戏见代码篇: 简易文件管理器

下期预告

下一篇我们将深入学习Python函数
学习函数是培养编程思维和软件工程能力的基础。
函数是构建程序的基本模块,是写出高质量代码的关键。

如果觉得有帮助,请关注+点赞+收藏,这是对我最大的鼓励!
如有问题,请评论区留言

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周五不部署

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值