目录
错误处理
错误大致可以分为三类:
- 程序本身的错误:比如拼写错误、语法错误、逻辑错误等,这些通常需要开发者修正。
- 用户输入导致的错误:比如要求输入数字,用户却输入了字母,这时程序需要对输入进行检查和处理。
- 不可预知的外部错误:比如磁盘空间不足、网络断开等,这些问题即使程序本身没有问题,也可能导致运行失败。
异常处理机制
Python 提供了 try...except...finally 结构,可以让我们专门处理异常情况。
# 即使发生异常,文件也会被正确关闭。
try:
file = open("test.txt", "w") # 打开文件
file.write("Hello, world!")
# 故意制造一个异常
1 / 0
except ZeroDivisionError:
print("除零错误!")
finally:
# 无论是否出错,这里都会执行
file.close()
print("文件已关闭")
# 可以针对不同的错误给出不同的提示
try:
# 获取用户输入并转换为整数,可能抛出ValueError异常
num = int(input("请输入一个整数:")) # 可能输入非数字
# 执行除法运算,可能抛出ZeroDivisionError异常
result = 10 / num # 可能除以0
# 捕获值错误异常(输入的不是有效数字时)
except ValueError:
# 输出错误提示信息
print("输入的不是有效的整数!")
# 捕获零除错误异常(除数为0时)
except ZeroDivisionError:
# 输出错误提示信息
print("不能除以0!")
# 如果try块中没有发生任何异常,则执行else块
else:
# 如果没有发生异常,会执行这里
# 输出计算结果
print("计算结果是:", result)
# 无论是否发生异常,finally块都会被执行
finally:
# 输出程序结束提示
print("程序结束。")如果一个函数内部发生了异常,但没有被捕获,异常会自动“传递”到调用它的函数,直到被捕获或者程序终止。
def func1():
return 10 / 0 # 这里会抛出异常
def func2():
return func1() # 异常会传递到这里
try:
func2() # 在这里捕获异常
except ZeroDivisionError as e:
print("捕获到异常:", e)没有捕获异常,Python会输出完整的错误信息。
def a():
return 1 / 0 # 这里出错
def b():
return a()
def c():
return b()
c()记录错误日志
有时候我们希望把错误信息保存下来,方便以后分析。Python的 logging 模块可以帮助我们记录详细的错误日志,日志会包含详细的错误类型和调用栈信息。
import logging # 导入日志模块
try:
10 / 0 # 故意制造异常
except Exception as e:
# 记录异常信息到日志
logging.error("程序出错了:", exc_info=True)
print("程序继续运行")主动抛出异常
# 定义一个自定义异常类,继承自Exception基类
class MyInputError(Exception):
"""自定义输入错误类型"""
# 使用pass关键字表示类体为空,仅继承父类功能
pass
# 定义一个检查正数的函数,接收一个数字参数
def check_positive(num):
# 判断输入的数字是否小于等于0
if num <= 0:
# 主动抛出自定义异常
# 使用raise关键字抛出自定义异常,并传递错误信息
raise MyInputError("输入必须是正数!")
# 如果数字为正数,则返回该数字
return num
# 使用try-except语句处理可能出现的异常
try:
# 调用check_positive函数,传入负数-5进行测试
check_positive(-5)
# 捕获MyInputError类型的异常,并将异常对象赋值给变量e
except MyInputError as e:
# 打印捕获到的自定义异常信息
print("捕获到自定义异常:", e)
# 捕获后重新抛出
def func():
try:
1 / 0
except ZeroDivisionError:
print("这里先记录一下异常")
raise # 重新抛出异常
try:
func()
except ZeroDivisionError:
print("最终在这里处理异常")代码调试
建议使用 Visual Studio Code、PyCharm 等现代 IDE,调试会更加直观。你只需要在代码行号旁边点击一下,就能设置断点,然后点击“调试”按钮,程序会自动在断点处暂停,可以在界面上查看变量、单步执行、甚至修改变量值;图形化界面更友好,调试效率更高,适合初学者和大型项目。
Python 自带 pdb 调试器,可以单步执行代码: python -m pdb your_script.py,调试器会停在第一行,可以用 n 命令逐行执行,用 p 变量名 查看变量值,用 q 退出调试。
import pdb
score_str = "0"
score = int(score_str)
pdb.set_trace() # 程序运行到这里会暂停,进入调试模式
print(100 / score)assert
测试则是通过编写测试用例,确保程序的正确性,如果断言失败,程序会抛出 AssertionError,断言适合用来检查那些“理论上不应该出错”的地方,帮助我们提前发现潜在问题。
通过命令行参数关闭所有assert语句,-O 参数会关闭所有assert语句,提高程序运行效率,如: python -O your_script.py。
def calculate_average(score_str):
score = int(score_str)
# 断言分数不能为0,否则会报错
assert score != 0, "分数不能为0!"
return 100 / score
def main():
calculate_average('0')
main()
def add(a, b):
return a + b
# 断言add(2, 3)的结果应该是5
assert add(2, 3) == 5, "加法结果不正确!"
print("测试通过")logging
相比 print,logging 模块更适合在实际开发中使用。它可以灵活地设置输出级别(如debug、info、warning、error),并且可以把日志写到文件里,方便后续分析与后期统一管理和关闭调试信息。
import logging
# 设置日志输出级别为INFO
logging.basicConfig(level=logging.INFO)
def calculate_average(score_str):
# 将字符串转换为整数
score = int(score_str)
# 用logging记录调试信息
logging.info("分数已转换为整数:%d", score) # INFO:root:分数已转换为整数:0
# 计算平均分
return 100 / score
def main():
calculate_average('0')
main()单元测试
单元测试用来“自动检查”小模块,比如一个函数、一个类是否能正确工作。
如下面的代码:
- 每个以
test_开头的方法就是一个测试用例。 assertEqual、assertTrue等是断言方法,用来判断结果是否符合预期。with self.assertRaises(...)用来检查是否抛出了指定的异常。
import unittest # 导入unittest模块
from mydict import MyDict # 假设上面的类保存在mydict.py文件中
# 定义一个测试类,继承自unittest.TestCase
class TestMyDict(unittest.TestCase):
def test_init(self):
# 测试初始化和属性访问
d = MyDict(a=1, b='hello')
self.assertEqual(d.a, 1) # 检查属性a的值
self.assertEqual(d.b, 'hello') # 检查属性b的值
self.assertTrue(isinstance(d, dict)) # 检查d是否是dict的子类
def test_key_access(self):
# 测试通过key访问和赋值
d = MyDict()
d['x'] = 100
self.assertEqual(d.x, 100) # 检查属性x的值
def test_attr_set(self):
# 测试通过属性赋值
d = MyDict()
d.y = 200
self.assertIn('y', d) # 检查字典里是否有'y'
self.assertEqual(d['y'], 200) # 检查key为'y'的值
def test_key_error(self):
# 测试访问不存在的key时抛出KeyError
d = MyDict()
# 使用with self.assertRaises(KeyError)来检查是否抛出了KeyError异常
with self.assertRaises(KeyError):
_ = d['not_exist']
def test_attr_error(self):
# 测试访问不存在的属性时抛出AttributeError
d = MyDict()
with self.assertRaises(AttributeError):
_ = d.not_exist
if __name__ == '__main__':
unittest.main() # 运行所有测试这种运行方式需要文件中有 if __name__ == '__main__': unittest.main() 才能运行测试, 相当于手动调用 unittest.main()。 或者使用unittest模块运行:
python -m unittest只运行指定的方法:
python -m unittest mydict_test.TestMyDict.test_attr_set有时候,每个测试方法运行前后都需要做一些准备和清理工作,比如连接和关闭数据库。可以避免在每个测试方法里重复写相同的代码,这时可以用 setUp() 和 tearDown() 方法:
class TestMyDict(unittest.TestCase):
def setUp(self):
# 每个测试方法运行前都会执行这里的代码
print('准备测试环境...')
def tearDown(self):
# 每个测试方法运行后都会执行这里的代码
print('清理测试环境...')文档测试
文档测试的核心思想是:把代码的使用示例直接写在注释里,然后让Python自动检查这些示例是否真的能运行并得到预期结果。 这样,别人看你的代码时,既能看到清晰的用法示例,还能保证这些示例是经过验证的,避免“文档和实际不符”的尴尬。
doctest
Python自带了 doctest 模块,可以自动提取docstring里的示例代码并运行,检查实际输出和注释里写的是否一致,如下代码:
- 只有直接运行这个脚本时,doctest才会执行(即
python xx.py)。 - 如果doctest全部通过,命令行不会有任何输出。
- 如果有错误,doctest会详细报告出错的示例和原因。
def my_abs(n):
'''
计算一个数的绝对值。
>>> my_abs(2)
2
>>> my_abs(-8)
8
'''
return n if n >= 0 else -n
if __name__ == '__main__':
import doctest # 导入doctest模块
doctest.testmod() # 自动运行当前模块中的所有doctest异常情况
只要异常类型和最后一行的错误信息能对上,doctest 就会判定通过。
def get_item(lst, idx):
'''
获取列表指定位置的元素。
>>> get_item([1, 2, 3], 1)
2
>>> get_item([1, 2, 3], 5)
Traceback (most recent call last):
...
IndexError: list index out of range
'''
return lst[idx]内置模块
文件与操作
os 模块
import os
# 获取当前工作目录(即当前Python脚本运行的文件夹)
print("当前工作目录:", os.getcwd())
# 切换到指定目录(如切换到C盘根目录,注意Windows下路径用\\或r'路径')
os.chdir(r'C:\\')
print("切换后的工作目录:", os.getcwd())
# 创建一个新文件夹
os.mkdir('test_folder') # 在当前目录下创建名为test_folder的文件夹
# 删除文件夹(只能删除空文件夹)
os.rmdir('test_folder')
# 列出当前目录下的所有文件和文件夹
print("当前目录内容:", os.listdir('.'))
# 获取操作系统的环境变量(如PATH)
print("系统PATH环境变量:", os.environ.get('PATH'))
# os.path
# 拼接路径(推荐用os.path.join,自动适配操作系统的分隔符)
full_path = os.path.join('folder', 'file.txt')
print("拼接后的路径:", full_path)
# 拆分路径,分离文件夹和文件名
folder, filename = os.path.split('folder/file.txt')
print("文件夹部分:", folder)
print("文件名部分:", filename)
# 判断文件是否存在
print("file.txt是否存在:", os.path.exists('file.txt'))
# 判断路径是否为文件
print("file.txt是文件吗:", os.path.isfile('file.txt'))
# 判断路径是否为文件夹
print("folder是文件夹吗:", os.path.isdir('folder'))
# 获取绝对路径
print("file.txt的绝对路径:", os.path.abspath('file.txt'))
# 获取文件扩展名
name, ext = os.path.splitext('file.txt')
print("文件名:", name)
print("扩展名:", ext)shutil 模块
import os
import shutil
# 复制文件(把a.txt复制为b.txt)
shutil.copy('a.txt', 'b.txt')
# 复制整个文件夹(把src_folder复制为dst_folder)
shutil.copytree('src_folder', 'dst_folder')
# 移动文件或文件夹(也可以用来重命名)
shutil.move('b.txt', 'new_b.txt') # 把b.txt移动或重命名为new_b.txt
# 删除文件
os.remove('new_b.txt')
# 删除整个文件夹及其内容
shutil.rmtree('dst_folder')glob 模块
import glob
# 查找当前目录下所有txt文件
txt_files = glob.glob('*.txt')
print("所有txt文件:", txt_files)
# 查找所有子文件夹下的txt文件(递归查找)
all_txt_files = glob.glob('**/*.txt', recursive=True)
print("所有子文件夹下的txt文件:", all_txt_files)tempfile 模块
import os
import tempfile
# 创建一个临时文件,返回文件对象
with tempfile.TemporaryFile(mode='w+t') as f:
f.write('这是临时文件内容')
f.seek(0) # 回到文件开头
print("临时文件内容:", f.read())
# 文件会在with语句结束后自动删除
# 创建一个临时目录
with tempfile.TemporaryDirectory() as tmpdirname:
print("临时目录路径:", tmpdirname)
# 可以在临时目录下创建文件
filepath = os.path.join(tmpdirname, 'temp.txt')
with open(filepath, 'w') as f:
f.write('写入临时文件')
# 读取刚才写入的内容
with open(filepath, 'r') as f:
print("读取临时文件内容:", f.read())
# 临时目录和里面的内容会自动删除fnmatch 模块
import fnmatch
# 判断文件名是否以.txt结尾
print(fnmatch.fnmatch('report.txt', '*.txt')) # 输出True
# 判断文件名是否以data_加两位数字结尾
print(fnmatch.fnmatch('data_01.csv', 'data_??.csv')) # 输出True
print(fnmatch.fnmatch('data_1.csv', 'data_??.csv')) # 输出False系统与运行环境
sys 模块
sys模块主要用于与Python解释器进行交互。你可以用它获取命令行参数、操作系统路径、退出程序等。它是写脚本和工具时非常常用的模块。
import sys # 导入sys模块
# sys.argv是一个列表,包含了命令行参数
print("所有命令行参数:", sys.argv) # 第一个参数是脚本名
# 获取第一个参数(脚本名)
print("脚本名:", sys.argv[0])
# 如果有额外参数,可以这样获取
if len(sys.argv) > 1:
print("第一个用户输入的参数:", sys.argv[1])
else:
print("没有输入额外参数")
# python 脚本名 参数1 参数2
# python 02.系统与运行环境.py hello
# 所有命令行参数: ['02.系统与运行环境.py', 'hello']
# 脚本名: 02.系统与运行环境.py
# 第一个用户输入的参数: hello
# sys模块可以获取和设置Python解释器的路径
# 获取Python解释器路径
print("Python解释器路径:", sys.executable)
# 设置Python解释器路径
sys.executable = "C:/Python311/python.exe"
print("程序即将退出")
sys.exit(0) # 0表示正常退出,非0表示异常退出
print("这行不会被执行") # 这行不会输出,因为上面已经退出platform 模块
platform 模块可以帮助你获取当前操作系统的类型、版本、Python 解释器的版本等信息。常用于需要根据不同系统做兼容性处理的场景。
import platform # 导入platform模块
# 获取操作系统名称
print("操作系统名称:", platform.system()) # 如 Windows、Linux、Darwin(macOS)
# 获取操作系统详细版本
print("操作系统详细版本:", platform.version())
# 获取完整平台信息
print("完整平台信息:", platform.platform())
# 获取Python版本
print("Python版本:", platform.python_version())
# 操作系统名称: Darwin
# 操作系统详细版本: Darwin Kernel Version 25.0.0: Wed Sep 17 21:41:45 PDT 2025; root:xnu-12377.1.9~141/RELEASE_ARM64_T6000
# 完整平台信息: macOS-26.0.1-arm64-arm-64bit
# Python版本: 3.11.11getopt/argparse 模块
写脚本时,经常需要从命令行获取参数。getopt和argparse都是用来解析命令行参数的模块。getopt适合简单参数,argparse功能更强大,推荐新手用argparse。
python demo.py -f config.txt --verbose -n 张三 -a 20 input1.txt input2.txt# demo_getopt.py
import sys, getopt
opts, args = getopt.getopt(sys.argv[1:], "f:n:a:", ["verbose"])
# 解析键值到变量
config = None
name = None
age = None
verbose = False
for opt, val in opts:
if opt == '-f':
config = val
elif opt == '-n':
name = val
elif opt == '-a':
age = int(val)
elif opt == '--verbose':
verbose = True
inputs = args # 剩余的位置参数
print("config =", config)
print("verbose =", verbose)
print("name =", name, "age =", age)
print("inputs =", inputs)
# demo_argparse.py
import argparse
parser = argparse.ArgumentParser(description="示例:读取配置并处理输入文件")
parser.add_argument("-f", "--config", required=True, help="配置文件路径")
parser.add_argument("--verbose", action="store_true", help="开启详细日志")
parser.add_argument("-n", "--name", required=True, help="你的名字")
parser.add_argument("-a", "--age", type=int, required=True, help="你的年龄")
parser.add_argument("inputs", nargs="+", help="要处理的输入文件")
args = parser.parse_args()
print("config =", args.config)
print("verbose =", args.verbose)
print("name =", args.name, "age =", args.age)
print("inputs =", args.inputs)logging 模块
import logging # 导入logging模块
# 记录一条信息
logging.info("这是一条普通信息") # 默认不会显示,因为默认级别是WARNING
# 记录一条警告
logging.warning("这是一个警告信息")
# 记录一条错误
logging.error("这是一个错误信息")
# 配置日志输出格式和级别
logging.basicConfig(
level=logging.INFO, # 设置日志级别为INFO
format="%(asctime)s - %(levelname)s - %(message)s" # 设置输出格式
)
logging.info("程序启动")
logging.warning("警告:磁盘空间不足")
logging.error("错误:文件未找到")subprocess 模块
subprocess 模块可以让你在 Python 程序中运行外部命令(比如调用系统的dir、ls、ping等),还能获取命令的输出结果;它是自动化运维、脚本开发的利器。
import subprocess
# 运行命令并获取输出(以Windows的dir命令为例,Linux下可用ls)
result = subprocess.run("dir", shell=True, capture_output=True, text=True)
# 打印命令的输出内容
print("命令输出:")
print(result.stdout)
# 运行一个命令
result = subprocess.run("ping 127.0.0.1 -n 2", shell=True)
# 判断命令是否成功执行(返回码为0表示成功)
if result.returncode == 0:
print("命令执行成功")
else:
print("命令执行失败,返回码:", result.returncode)日期和时间
time 模块
time模块主要用于处理时间戳、获取当前时间、让程序休眠等。它和操作系统的时间紧密相关,适合做一些底层的时间操作。
import time
# 获取当前时间戳(单位:秒,浮点数)
timestamp = time.time()
print("当前时间戳:", timestamp)
# 获取当前本地时间的结构体
local_time = time.localtime()
print("本地时间结构体:", local_time)
# 将时间戳转换为本地时间结构体
t = 1700000000
print("时间戳1700000000对应的本地时间:", time.localtime(t))
# 将本地时间结构体转换为字符串
time_str = time.strftime("%Y-%m-%d %H:%M:%S", local_time)
print("格式化后的本地时间:", time_str)
# 将字符串时间转换为时间结构体
parsed_time = time.strptime("2024-01-01 12:00:00", "%Y-%m-%d %H:%M:%S")
print("解析后的时间结构体:", parsed_time)
print("开始休眠2秒")
time.sleep(2) # 让程序暂停2秒
print("2秒后继续执行")| 方法 | 字母 | 含义 | 方向 | 助记词 |
|---|---|---|---|---|
| strftime | f | Format | 对象 → 字符串 | ”Format” |
| strptime | p | Parse | 字符串 → 对象 | ”Parse” |
datetime 模块
datetime模块是Python中功能最强大的日期和时间处理模块。它可以方便地获取当前日期、时间,进行加减、比较等操作。
import datetime
# 获取当前日期和时间
now = datetime.datetime.now()
print("当前日期和时间:", now)
# 获取当前日期
today = datetime.date.today()
print("今天的日期:", today)
# 创建一个指定日期的date对象
d = datetime.date(2025, 12, 25)
print("指定日期:", d)
# 创建一个指定日期和时间的datetime对象
dt = datetime.datetime(2025, 12, 25, 15, 30, 0)
print("指定日期和时间:", dt)
# 加3天
three_days_later = now + datetime.timedelta(days=3)
print("三天后:", three_days_later)
# 减2小时
two_hours_ago = now - datetime.timedelta(hours=2)
print("两小时前:", two_hours_ago)
# datetime对象转为字符串
now = datetime.datetime.now()
now_str = now.strftime("%Y-%m-%d %H:%M:%S")
print("格式化后的时间字符串:", now_str)
# 字符串转为datetime对象
dt = datetime.datetime.strptime("2025-01-01 08:30:00", "%Y-%m-%d %H:%M:%S")
print("解析后的datetime对象:", dt)calendar 模块
calendar模块可以用来生成日历、判断某天是星期几、判断闰年等,适合做日历和日期分析相关的功能。
import calendar
# 打印2025年5月的日历
print(calendar.month(2025, 5))
# May 2025
# Mo Tu We Th Fr Sa Su
# 1 2 3 4
# 5 6 7 8 9 10 11
# 12 13 14 15 16 17 18
# 19 20 21 22 23 24 25
# 26 27 28 29 30 31
# 判断2025年是否为闰年
is_leap = calendar.isleap(2025)
print("2025年是闰年吗?", is_leap)
# 获取2025年5月的每周分布(每周是一个元组,0表示周一)
month_days = calendar.monthcalendar(2025, 5)
print("2025年5月的每周分布:", month_days)
# 0表示周一,6表示周日
weekday = calendar.weekday(2025, 5, 1)
print("2025年5月1日是: 星期", weekday + 1)数学与数字处理
math 模块
import math
# 计算平方根
print("16的平方根:", math.sqrt(16)) # 输出4.0
# 计算绝对值
print("绝对值:", math.fabs(-5)) # 输出5.0
# 计算幂(2的3次方)
print("2的3次方:", math.pow(2, 3)) # 输出8.0
# 计算正弦、余弦、正切
print("sin(30°):", math.sin(math.radians(30))) # 先将角度转为弧度
print("cos(60°):", math.cos(math.radians(60)))
print("tan(45°):", math.tan(math.radians(45)))
# 常用常数
print("圆周率π:", math.pi)
print("自然对数e:", math.e)
# 计算自然对数(以e为底)
print("ln(10):", math.log(10)) # 默认以e为底
# 计算以10为底的对数
print("log10(100):", math.log10(100)) # 输出2.0
# 向上取整
print("向上取整3.2:", math.ceil(3.2)) # 输出4
# 向下取整
print("向下取整3.8:", math.floor(3.8)) # 输出3random 模块
import random
# 生成1到10之间的随机整数(包含1和10)
print("随机整数:", random.randint(1, 10))
# 生成0到1之间的随机小数
print("随机小数:", random.random())
# 从列表中随机选择一个元素
fruits = ["苹果", "香蕉", "橙子"]
print("随机选择水果:", random.choice(fruits))
# 打乱列表顺序
random.shuffle(fruits)
print("打乱后的水果列表:", fruits)
# 生成2到10之间,步长为2的随机偶数
print("随机偶数:", random.randrange(2, 11, 2)) # 可能输出2、4、6、8、10decimal 模块
decimal 模块可以进行高精度的十进制计算,适合对精度要求很高的场合,比如财务、科学计算等。
from decimal import Decimal, getcontext
# 普通浮点数的加法(可能有精度误差)
print("0.1 + 0.2 =", 0.1 + 0.2) # 输出0.30000000000000004
# 用Decimal进行高精度加法
a = Decimal("0.1")
b = Decimal("0.2")
print("Decimal高精度加法:", a + b) # 输出0.3
# 设置全局小数精度为4位
getcontext().prec = 4
# 进行高精度运算
result = Decimal("1.23456") / Decimal("3")
print("保留4位有效数字的结果:", result)fractions 模块
fractions模块可以用来进行分数的加减乘除,结果也是分数,非常适合需要精确分数表示的场景。
from fractions import Fraction
# 创建分数1/3
f1 = Fraction(1, 3)
print("分数1/3:", f1)
# 由字符串创建分数
f2 = Fraction("2/5")
print("分数2/5:", f2)
a = Fraction(1, 3)
b = Fraction(1, 6)
# 分数加法
print("1/3 + 1/6 =", a + b)
# 分数乘法
print("1/3 * 1/6 =", a * b)statistics 模块
statistics模块可以方便地计算均值、中位数、方差等常用统计量,适合数据分析和科学计算。
import statistics
data = [1, 2, 3, 4, 5, 6]
# 计算均值
print("均值:", statistics.mean(data))
# 计算中位数
print("中位数:", statistics.median(data))
# 计算方差
# 方差指数据与均值之间的偏离程度
print("方差:", statistics.variance(data))
# 计算众数(出现次数最多的数)
print("众数:", statistics.mode(data))字符串与文本处理
re 模块
re模块用于复杂的字符串匹配、查找、替换等操作;正则表达式是一种用特殊符号描述字符串规则的“语言”,可以高效地处理各种文本格式。
import re
# 判断字符串是否是手机号(以1开头,11位数字)
phone = "13812345678"
pattern = r"^1\d{10}$" # 正则表达式:1开头,后面10个数字
if re.match(pattern, phone):
print("手机号格式正确")
else:
print("手机号格式不正确")
# 提取字符串中的所有数字
text = "小明今年18岁,身高175cm"
numbers = re.findall(r"\d+", text) # 匹配所有连续数字
print("提取到的数字:", numbers)
# 提取到的数字: ['18', '175']
# 把字符串中的数字全部替换为X
text = "房间号:308,电话:123456"
new_text = re.sub(r"\d+", "X", text)
print("替换后的文本:", new_text)
# 替换后的文本: 房间号:X,电话:Xstring 模块
string模块提供了很多常用的字符串处理工具,比如大小写转换、字符集常量等。虽然大部分字符串操作可以直接用str对象的方法,但string模块有些特殊用途。
import string
# 获取所有小写字母
print("小写字母:", string.ascii_lowercase)
# 小写字母: abcdefghijklmnopqrstuvwxyz
# 获取所有大写字母
print("大写字母:", string.ascii_uppercase)
# 大写字母: ABCDEFGHIJKLMNOPQRSTUVWXYZ
# 获取所有数字字符
print("数字字符:", string.digits)
# 数字字符: 0123456789
# 用f-string格式化字符串(推荐)
name = "小明"
age = 18
print(f"大家好,我是{name},今年{age}岁。")
# 用str.format格式化字符串
print("大家好,我是{},今年{}岁。".format(name, age))textwrap 模块
textwrap模块可以让长文本自动换行,适合在命令行或输出到文件时美化排版。
import textwrap
# 一段很长的文本
long_text = "Python是一门非常流行的编程语言。它语法简洁,功能强大,应用广泛。"
# 自动换行,每行最多20个字符
wrapped = textwrap.fill(long_text, width=20)
print(wrapped)
# 带有缩进的多行文本
text = """
这是第一行。
这是第二行,有更多缩进。
这是第三行。
"""
# 去除所有行的多余缩进
dedented = textwrap.dedent(text)
print(dedented)difflib 模块
difflib模块可以用来比较两个字符串或文本的差异,常用于做文本对比、生成差异报告等。
import difflib
text1 = "Python是一门很棒的语言。"
text2 = "Python是一门非常棒的语言!"
# 生成差异对比
diff = difflib.ndiff(text1, text2)
print("\n".join(diff))
text1 = """Python是一门很棒的语言。
适合新手学习。"""
text2 = """Python是一门非常棒的语言!
适合零基础新手学习。"""
# 生成HTML格式的差异报告
d = difflib.HtmlDiff()
html = d.make_file(text1.splitlines(), text2.splitlines())
with open("diff_report.html", "w", encoding="utf-8") as f:
f.write(html)
print("差异报告已生成:diff_report.html")文件格式与数据存储
json 模块
import json
# 定义一个Python字典
data = {"name": "小明", "age": 18, "score": [90, 85, 92]}
# 将Python对象转换为JSON字符串
json_str = json.dumps(data, ensure_ascii=False) # ensure_ascii=False可以输出中文
print("转换后的JSON字符串:", json_str)
# 定义一个JSON格式的字符串
json_str = '{"name": "小明", "age": 18, "score": [90, 85, 92]}'
# 将JSON字符串转换为Python对象
data = json.loads(json_str)
print("转换后的Python对象:", data)
# 写入JSON文件
data = {"city": "北京", "temp": 25}
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False)
# 读取JSON文件
with open("data.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
print("从文件读取的数据:", loaded)csv 模块
import csv
# 准备要写入CSV文件的数据,使用二维列表结构
# 第一行是表头,后面的行是具体的学生数据
rows = [
# 表头行,定义各列的名称
["姓名", "年龄", "成绩"],
# 第一个学生的信息:姓名、年龄、成绩
["小明", 18, 90],
["小红", 17, 95],
]
# 使用with语句打开文件,确保文件会被正确关闭
# 'w'表示写入模式,newline=''防止出现空行,encoding='utf-8'确保中文正确显示
with open("students.csv", "w", newline="", encoding="utf-8") as f:
# 创建CSV写入器对象,用于将数据写入文件
writer = csv.writer(f)
# 一次性写入所有行数据到CSV文件
writer.writerows(rows)
# 打印提示信息,告知用户文件写入操作已完成
print("CSV文件写入完成")
# 读取CSV文件
with open("students.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
for row in reader:
print("读取到一行:", row)
# 取到一行: ['姓名', '年龄', '成绩']
# 读取到一行: ['小明', '18', '90']
# 读取到一行: ['小红', '17', '95']configparser 模块
configparser 模块用于读取和写入类似于Windows ini格式的配置文件,常用于保存程序的配置信息。
假设有一个配置文件 config.ini 内容如下:
[DEFAULT]
username = admin
password = 123456
[server]
host = localhost
port = 8080import configparser
# 创建配置解析器对象
config = configparser.ConfigParser()
# 读取配置文件
config.read('config.ini', encoding='utf-8')
# 获取DEFAULT区的username
print("用户名:", config['DEFAULT']['username'])
# 获取server区的host和port
print("服务器地址:", config['server']['host'])
print("服务器端口:", config['server']['port'])
# 添加内容
config['DEFAULT'] = {'username': 'admin', 'password': '123456'}
config['server'] = {'host': 'localhost', 'port': '8080'}
# 写入到文件
with open('config.ini', 'w', encoding='utf-8') as f:
config.write(f)
print("配置文件写入完成")pickle 模块
pickle模块可以把Python对象保存到文件中,也可以从文件中恢复出来。常用于保存程序运行状态、缓存数据等。
import pickle
# 定义一个Python对象
data = {"name": "小明", "age": 18, "score": [90, 85, 92]}
# 序列化并写入文件
with open("data.pkl", "wb") as f: # 注意用二进制写入
pickle.dump(data, f)
print("对象已序列化保存")
# 从文件读取并反序列化
with open("data.pkl", "rb") as f:
loaded = pickle.load(f)
print("反序列化得到的对象:", loaded)加密和安全
哈希算法
哈希算法(也叫散列算法)是一种将任意长度的数据“压缩”成固定长度字符串的算法。常见的哈希算法有MD5、SHA1、SHA256等。哈希值常用于密码存储、文件校验、防篡改等场景。主要特点:
- 相同输入一定得到相同输出
- 不同输入得到的输出尽量不同
- 不能通过哈希值反推出原始内容(不可逆)
import hashlib
# 原始字符串
text = "hello world"
# 创建MD5哈希对象
md5 = hashlib.md5()
# 必须先将字符串编码为字节
md5.update(text.encode("utf-8"))
# 获取16进制的哈希值
print("MD5哈希值:", md5.hexdigest())
# 导入hashlib模块,用于计算各种哈希值
# 使用with语句打开文件,'rb'模式表示以二进制只读方式打开
# 打开文件,读取内容
with open("README.md", "rb") as f:
# 创建一个SHA1哈希对象
sha1 = hashlib.sha1()
# 使用无限循环来分块读取文件内容,这样可以处理大文件而不会占用过多内存
# 分块读取,适合大文件
while True:
# 每次读取1024字节的数据
data = f.read(1024)
# 如果读取到的数据为空,说明文件已经读取完毕
if not data:
# 跳出循环
break
# 将读取到的数据块更新到SHA1哈希对象中
sha1.update(data)
# 计算最终的SHA1哈希值并以十六进制字符串形式输出
print("文件的SHA1哈希值:", sha1.hexdigest())
text = "python123"
# 计算MD5
md5 = hashlib.md5(text.encode("utf-8")).hexdigest()
print("MD5:", md5)
# 计算SHA1
sha1 = hashlib.sha1(text.encode("utf-8")).hexdigest()
print("SHA1:", sha1)
# 计算SHA256
sha256 = hashlib.sha256(text.encode("utf-8")).hexdigest()
print("SHA256:", sha256)hmac 模块
HMAC(Hash-based Message Authentication Code,基于哈希的消息认证码)是一种常用的消息加密校验方式。它结合了哈希算法和密钥,可以防止数据在传输过程中被篡改。常用于:
- 网络通信中的数据完整性校验
- API接口的签名认证
import hashlib
import hmac
# 消息内容
message = b"hello, world"
# 密钥(双方约定的“密码”)
key = b"my_secret_key"
# 创建HMAC对象,指定密钥和哈希算法
h = hmac.new(key, message, digestmod=hashlib.sha256)
# 获取16进制的HMAC值
print("HMAC签名:", h.hexdigest())
def verify_hmac(message, key, received_hmac):
# 重新生成HMAC
h = hmac.new(key, message, digestmod=hashlib.sha256)
# 比较HMAC值
return h.hexdigest() == received_hmac
# 假设收到如下数据
msg = b"hello, world"
key = b"my_secret_key"
received = hmac.new(key, msg, digestmod=hashlib.sha256).hexdigest()
# 校验
if verify_hmac(msg, key, received):
print("数据未被篡改,校验通过")
else:
print("数据被篡改,校验失败")
网络与互联网
urllib 模块
urllib模块是Python自带的网络请求工具,可以用来抓取网页、下载文件、解析URL等。常用子模块有urllib.request、urllib.parse等。
from urllib import request, parse
# 发送GET请求,获取网页内容
response = request.urlopen("https://www.example.com")
# 读取网页内容(字节类型)
html = response.read()
# 将字节内容解码为字符串
print("网页内容:", html.decode("utf-8"))
url = "https://www.example.com/search?q=python&lang=zh"
# 解析URL为各部分
result = parse.urlparse(url)
print("协议:", result.scheme)
print("主机:", result.netloc)
print("路径:", result.path)
print("查询参数:", result.query)
# 字典转为URL参数字符串
params = {"q": "python", "lang": "zh"}
query_str = parse.urlencode(params)
print("编码后的参数:", query_str)
# URL参数字符串转为字典
parsed = parse.parse_qs("q=python &lang=zh")
print("解码后的参数:", parsed)http.client 模块
http.client模块可以让你用底层方式发送HTTP请求,适合需要自定义请求头、方法等高级用法。
import http.client
# 创建HTTP连接对象
conn = http.client.HTTPSConnection("www.example.com")
# 发送GET请求
conn.request("GET", "/")
# 获取响应
response = conn.getresponse()
print("状态码:", response.status)
print("响应内容:", response.read().decode("utf-8"))
# 关闭连接
conn.close()
# 创建一个HTTPS连接对象,连接到www.example.com服务器
conn = http.client.HTTPSConnection("www.example.com")
# 定义要发送的POST数据,格式为URL编码的字符串
params = "name=Tom&age=18"
# 设置HTTP请求头,指定内容类型为表单数据格式
headers = {"Content-type": "application/x-www-form-urlencoded"}
# 发送POST请求到/submit路径,包含参数和请求头
conn.request("POST", "/submit", params, headers)
# 获取服务器的响应对象
response = conn.getresponse()
# 读取响应内容并解码为UTF-8格式,然后打印输出
print("POST响应内容:", response.read().decode("utf-8"))
# 关闭HTTP连接,释放资源
conn.close()smtplib 模块
import smtplib
from email.mime.text import MIMEText
# 邮件内容
msg = MIMEText("你好,这是一封测试邮件。", "plain", "utf-8")
# 发件人、收件人、主题
msg["From"] = "from@qq.com"
msg["To"] = "to@qq.com"
msg["Subject"] = "测试邮件"
# 连接QQ邮箱SMTP服务器并登录
server = smtplib.SMTP_SSL("smtp.qq.com", 465)
server.login("from@qq.com", "your_password")
# 发送邮件
server.sendmail("from@qq.com", ["to@qq.com"], msg.as_string())
# 关闭连接
server.quit()
print("邮件发送成功")socket 模块
socket模块是Python最底层的网络通信接口,可以实现自定义的网络协议、聊天程序等。
import socket
# 创建TCP套接字
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定IP和端口
server.bind(("127.0.0.1", 8888))
# 开始监听 1指的是最大连接数
server.listen(1)
print("服务器已启动,等待连接...", server.getsockname())
# 接受客户端连接
conn, addr = server.accept()
print("连接来自:", addr)
# 接收数据
data = conn.recv(1024)
print("收到客户端数据:", data.decode("utf-8"))
# 发送回复
conn.send(b"Hello, client!")
# 关闭连接
conn.close()
server.close()socket_server.pythonimport socket
# 创建TCP套接字
# AF_INET: 使用IPv4地址族
# SOCK_STREAM: 使用TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
client.connect(("127.0.0.1", 8888))
# 发送数据
client.send(b"Hello, server!")
# 接收数据
data = client.recv(1024)
print("收到服务器回复:", data.decode("utf-8"))
# 关闭连接
client.close()socket_client.py其它模块
copy 模块
import copy
# 定义一个嵌套列表
lst1 = [1, 2, [3, 4]]
# 浅拷贝:只复制最外层,内部嵌套对象还是同一个
lst2 = copy.copy(lst1)
lst2[2][0] = 99
print("浅拷贝后lst1:", lst1) # [1, 2, [99, 4]]
# 深拷贝:递归复制所有层级,完全独立
lst3 = copy.deepcopy(lst1)
lst3[2][0] = 100
print("深拷贝后lst1:", lst1) # [1, 2, [99, 4]]
print("深拷贝后lst3:", lst3) # [1, 2, [100, 4]]enum 模块
from enum import Enum
# 定义一个星期的枚举类型
class Weekday(Enum):
MON = 1
TUE = 2
WED = 3
THU = 4
FRI = 5
SAT = 6
SUN = 7
# 使用枚举
today = Weekday.MON
print("今天是:", today)
print("今天的值:", today.value)
print("今天的名字:", today.name)uuid 模块
import uuid
# 生成一个随机的UUID(版本4)
unique_id = uuid.uuid4()
print("随机UUID:", unique_id)
# 生成基于名字的UUID(版本5)
name_id = uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
print("基于名字的UUID:", name_id)base64 模块
import base64
# 原始字符串
text = "hello world"
# 编码为字节
text_bytes = text.encode("utf-8")
# Base64编码
encoded = base64.b64encode(text_bytes)
print("Base64编码:", encoded)
# Base64解码
decoded = base64.b64decode(encoded)
print("解码后字符串:", decoded.decode("utf-8"))
# 读取文件并编码为Base64
with open("README.md", "rb") as f:
img_data = f.read()
encoded = base64.b64encode(img_data)
print("Base64编码前10字节:", encoded[:10])
# 解码Base64并写入新文件
with open("README.md", "wb") as f:
f.write(base64.b64decode(encoded))struct 模块
import struct
# `i`表示整数,`f`表示浮点数,顺序要和打包时一致。
# 打包:把整数12345和浮点数3.14编码为二进制
packed = struct.pack('if', 12345, 3.14)
print("打包后的二进制数据:", packed)
# 解包:从二进制数据还原为原始数据
unpacked = struct.unpack('if', packed)
print("解包后的数据:", unpacked)typing 模块
typing模块用于为变量、函数参数和返回值添加类型提示,让代码更规范、易读,适合团队协作和大型项目。
from typing import List, Optional, Tuple
# 定义一个加法函数,参数x和y都是整数类型,返回值也是整数类型
def add(x: int, y: int) -> int:
# 返回两个数的和
return x + y
# 定义一个问候函数,参数names是字符串列表,无返回值
def greet(names: List[str]) -> None:
# 遍历名字列表中的每个名字
for name in names:
# 打印问候语和当前名字
print("你好,", name)
# 使用类型提示
# 调用add函数计算2+3的结果
result = add(2, 3)
# 调用greet函数问候小明和小红
greet(["小明", "小红"])
# 定义一个查找用户的函数,参数是用户ID(整数类型),返回值是可选的元组(包含姓名和年龄)
# Optional[Tuple[str, int]] 表示返回值可以是一个元组,也可以是None。
def find_user(user_id: int) -> Optional[Tuple[str, int]]:
# 假设查找不到返回None
# 如果用户ID等于1,返回用户信息
if user_id == 1:
# 返回包含姓名和年龄的元组
return ("小明", 18)
# 如果用户ID不等于1,返回None表示未找到
else:
return None
# 调用函数查找ID为1的用户并打印结果
print(find_user(1))
# 调用函数查找ID为2的用户并打印结果
print(find_user(2))配套代码:vsme/learn-python