函数与模块
函数是组织代码的基本单位,它将相关的代码组织在一起,实现特定的功能。模块则是更高层次的代码组织方式,可以包含多个函数、类和变量。
代码组织层次图:
┌─────────────────────────────────────────────┐
│ 代码组织结构 │
├─────────────────────────────────────────────┤
│ │
│ 语句 → 函数 → 模块 → 包 → 项目 │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ 基本 代码 文件 目录 完整 │
│ 操作 块 .py 结构 应用 │
│ │
└─────────────────────────────────────────────┘
定义函数(def)
函数是可重用的代码块,使用def关键字定义。
1. 基本函数定义
# 最简单的函数
def greet():
"""打招呼函数"""
print("Hello, World!")
# 调用函数
greet()
# 带参数的函数
def greet_person(name):
"""向指定人员打招呼"""
print(f"Hello, {name}!")
# 调用带参数的函数
greet_person("Alice")
greet_person("Bob")
# 带返回值的函数
def add_numbers(a, b):
"""计算两个数的和"""
result = a + b
return result
# 使用返回值
sum_result = add_numbers(5, 3)
print(f"5 + 3 = {sum_result}")
# 多个返回值
def get_name_age():
"""返回姓名和年龄"""
return "张三", 25
# 接收多个返回值
name, age = get_name_age()
print(f"姓名: {name}, 年龄: {age}")
# 或者作为元组接收
info = get_name_age()
print(f"信息: {info}")
2. 函数文档字符串(Docstring)
def calculate_area(length, width):
"""
计算矩形面积
Args:
length (float): 矩形长度
width (float): 矩形宽度
Returns:
float: 矩形面积
Examples:
>>> calculate_area(5, 3)
15
>>> calculate_area(2.5, 4)
10.0
"""
if length <= 0 or width <= 0:
raise ValueError("长度和宽度必须大于0")
return length * width
# 访问文档字符串
print(calculate_area.__doc__)
# 使用help()函数查看文档
help(calculate_area)
# 测试函数
print(f"矩形面积: {calculate_area(5, 3)}")
print(f"矩形面积: {calculate_area(2.5, 4)}")
3. 函数的最佳实践
# ✅ 好的函数设计
def is_prime(n):
"""
判断一个数是否为质数
Args:
n (int): 要判断的数字
Returns:
bool: 如果是质数返回True,否则返回False
"""
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
# 只需要检查到sqrt(n)
for i in range(3, int(n ** 0.5) + 1, 2):
if n % i == 0:
return False
return True
# ✅ 单一职责原则
def format_currency(amount):
"""格式化货币显示"""
return f"¥{amount:,.2f}"
def calculate_tax(amount, rate):
"""计算税款"""
return amount * rate
def get_total_with_tax(amount, tax_rate):
"""计算含税总价"""
tax = calculate_tax(amount, tax_rate)
total = amount + tax
return total
# 使用示例
price = 1000
tax_rate = 0.1
tax_amount = calculate_tax(price, tax_rate)
total_price = get_total_with_tax(price, tax_rate)
print(f"商品价格: {format_currency(price)}")
print(f"税款: {format_currency(tax_amount)}")
print(f"总价: {format_currency(total_price)}")
# ❌ 避免的坏习惯
# def bad_function(x, y, z, flag1, flag2, mode, option):
# # 参数太多,难以理解和使用
# pass
# def do_everything():
# # 函数做太多事情,违反单一职责原则
# pass
参数类型
Python函数支持多种参数类型,提供了灵活的参数传递方式。
1. 位置参数
def introduce(name, age, city):
"""介绍个人信息"""
print(f"我叫{name},今年{age}岁,来自{city}")
# 按位置传递参数
introduce("张三", 25, "北京")
introduce("李四", 30, "上海")
# 参数顺序很重要
# introduce(25, "张三", "北京") # 错误的顺序
# 使用关键字参数可以改变顺序
introduce(age=28, name="王五", city="广州")
introduce("赵六", city="深圳", age=32) # 混合使用
2. 默认参数
def greet(name, greeting="Hello", punctuation="!"):
"""打招呼函数,支持自定义问候语和标点"""
return f"{greeting}, {name}{punctuation}"
# 使用默认参数
print(greet("Alice")) # Hello, Alice!
print(greet("Bob", "Hi")) # Hi, Bob!
print(greet("Charlie", "Hey", ".")) # Hey, Charlie.
print(greet("David", punctuation="?")) # Hello, David?
# ⚠️ 默认参数的陷阱:可变对象
def bad_append(item, target_list=[]):
"""错误的默认参数使用"""
target_list.append(item)
return target_list
# 问题演示
result1 = bad_append(1)
result2 = bad_append(2)
print(f"result1: {result1}") # [1, 2] - 不是期望的[1]
print(f"result2: {result2}") # [1, 2] - 不是期望的[2]
# ✅ 正确的做法
def good_append(item, target_list=None):
"""正确的默认参数使用"""
if target_list is None:
target_list = []
target_list.append(item)
return target_list
# 正确的结果
result3 = good_append(1)
result4 = good_append(2)
print(f"result3: {result3}") # [1]
print(f"result4: {result4}") # [2]
3. 可变参数(*args)
def sum_all(*numbers):
"""计算所有数字的和"""
total = 0
for num in numbers:
total += num
return total
# 可以传递任意数量的参数
print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
print(sum_all()) # 0
# 传递列表或元组
numbers_list = [1, 2, 3, 4, 5]
print(sum_all(*numbers_list)) # 使用*解包
def print_info(name, *hobbies):
"""打印姓名和爱好"""
print(f"姓名: {name}")
if hobbies:
print(f"爱好: {', '.join(hobbies)}")
else:
print("没有提供爱好信息")
print_info("张三", "读书", "游泳", "编程")
print_info("李四")
# 实际应用:日志函数
def log_message(level, message, *details):
"""记录日志信息"""
print(f"[{level}] {message}")
for detail in details:
print(f" - {detail}")
log_message("INFO", "用户登录", "用户ID: 12345", "IP: 192.168.1.1", "时间: 2023-01-01 10:00:00")
log_message("ERROR", "数据库连接失败")
4. 关键字参数(**kwargs)
def create_profile(**info):
"""创建用户档案"""
print("用户档案:")
for key, value in info.items():
print(f" {key}: {value}")
# 可以传递任意数量的关键字参数
create_profile(name="张三", age=25, city="北京", job="工程师")
create_profile(name="李四", email="lisi@example.com")
# 结合位置参数和关键字参数
def advanced_function(required_arg, *args, **kwargs):
"""演示各种参数类型"""
print(f"必需参数: {required_arg}")
print(f"位置参数: {args}")
print(f"关键字参数: {kwargs}")
advanced_function("必需的", "额外1", "额外2", name="张三", age=25)
# 实际应用:配置函数
def connect_database(host, port=5432, **config):
"""连接数据库"""
print(f"连接到 {host}:{port}")
print("配置参数:")
for key, value in config.items():
print(f" {key}: {value}")
connect_database(
"localhost",
database="mydb",
username="admin",
password="secret",
timeout=30,
ssl=True
)
5. 参数解包
# 解包列表/元组作为位置参数
def calculate(a, b, c):
return a + b * c
values = [2, 3, 4]
result = calculate(*values) # 等价于 calculate(2, 3, 4)
print(f"计算结果: {result}")
# 解包字典作为关键字参数
def create_user(name, age, email):
return f"用户: {name}, 年龄: {age}, 邮箱: {email}"
user_data = {"name": "张三", "age": 25, "email": "zhangsan@example.com"}
user_info = create_user(**user_data)
print(user_info)
# 混合解包
def complex_function(a, b, c=10, d=20):
return a + b + c + d
args = [1, 2]
kwargs = {"c": 30, "d": 40}
result = complex_function(*args, **kwargs)
print(f"复杂函数结果: {result}")
# 实际应用:函数装饰器中的参数传递
def timer_decorator(func):
"""计时装饰器"""
import time
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs) # 传递所有参数
end_time = time.time()
print(f"{func.__name__} 执行时间: {end_time - start_time:.4f}秒")
return result
return wrapper
@timer_decorator
def slow_function(n):
"""模拟耗时操作"""
total = 0
for i in range(n):
total += i
return total
result = slow_function(1000000)
print(f"计算结果: {result}")
返回值
函数可以返回不同类型的值,包括单个值、多个值或不返回值。
1. 单个返回值
def square(x):
"""计算平方"""
return x ** 2
def get_grade(score):
"""根据分数获取等级"""
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
print(f"5的平方: {square(5)}")
print(f"85分的等级: {get_grade(85)}")
2. 多个返回值
def divide_with_remainder(dividend, divisor):
"""除法运算,返回商和余数"""
quotient = dividend // divisor
remainder = dividend % divisor
return quotient, remainder
# 接收多个返回值
q, r = divide_with_remainder(17, 5)
print(f"17 ÷ 5 = {q} 余 {r}")
# 作为元组接收
result = divide_with_remainder(17, 5)
print(f"结果元组: {result}")
def get_statistics(numbers):
"""计算数字列表的统计信息"""
if not numbers:
return None, None, None, None
total = sum(numbers)
count = len(numbers)
average = total / count
maximum = max(numbers)
minimum = min(numbers)
return total, average, maximum, minimum
# 使用统计函数
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
total, avg, max_val, min_val = get_statistics(data)
print(f"总和: {total}, 平均值: {avg:.2f}, 最大值: {max_val}, 最小值: {min_val}")
3. 返回复杂数据结构
def analyze_text(text):
"""分析文本,返回详细统计信息"""
words = text.split()
analysis = {
"word_count": len(words),
"char_count": len(text),
"char_count_no_spaces": len(text.replace(" ", "")),
"longest_word": max(words, key=len) if words else "",
"shortest_word": min(words, key=len) if words else "",
"word_frequency": {}
}
# 计算词频
for word in words:
word_lower = word.lower().strip(".,!?;:")
analysis["word_frequency"][word_lower] = analysis["word_frequency"].get(word_lower, 0) + 1
return analysis
# 使用文本分析函数
sample_text = "Python is great. Python is powerful. Python is easy to learn."
analysis_result = analyze_text(sample_text)
print("文本分析结果:")
for key, value in analysis_result.items():
if key != "word_frequency":
print(f" {key}: {value}")
print(" 词频统计:")
for word, freq in analysis_result["word_frequency"].items():
print(f" {word}: {freq}")
4. 早期返回(Early Return)
def validate_user_input(username, password, email):
"""验证用户输入,使用早期返回模式"""
# 检查用户名
if not username:
return False, "用户名不能为空"
if len(username) < 3:
return False, "用户名至少需要3个字符"
if not username.isalnum():
return False, "用户名只能包含字母和数字"
# 检查密码
if not password:
return False, "密码不能为空"
if len(password) < 8:
return False, "密码至少需要8个字符"
# 检查邮箱
if not email:
return False, "邮箱不能为空"
if "@" not in email or "." not in email:
return False, "邮箱格式不正确"
# 所有验证通过
return True, "验证通过"
# 测试验证函数
test_cases = [
("", "password123", "test@example.com"),
("ab", "password123", "test@example.com"),
("user@name", "password123", "test@example.com"),
("username", "123", "test@example.com"),
("username", "password123", "invalid-email"),
("username", "password123", "test@example.com")
]
for i, (user, pwd, mail) in enumerate(test_cases, 1):
is_valid, message = validate_user_input(user, pwd, mail)
print(f"测试{i}: {message}")
匿名函数(lambda函数)
lambda函数是一种创建小型匿名函数的方式,通常用于简单的操作。
1. 基本lambda函数
# 基本语法:lambda 参数: 表达式
square = lambda x: x ** 2
print(f"5的平方: {square(5)}")
# 等价的普通函数
def square_normal(x):
return x ** 2
print(f"5的平方(普通函数): {square_normal(5)}")
# 多个参数的lambda
add = lambda x, y: x + y
print(f"3 + 4 = {add(3, 4)}")
# 带默认参数的lambda
greet = lambda name, greeting="Hello": f"{greeting}, {name}!"
print(greet("Alice"))
print(greet("Bob", "Hi"))
2. lambda与内置函数结合
# 与map()函数结合
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(f"平方数: {squared}")
# 与filter()函数结合
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f"偶数: {even_numbers}")
# 与sorted()函数结合
students = [
{"name": "Alice", "grade": 85},
{"name": "Bob", "grade": 90},
{"name": "Charlie", "grade": 78},
{"name": "David", "grade": 92}
]
# 按成绩排序
sorted_by_grade = sorted(students, key=lambda student: student["grade"])
print("按成绩排序:")
for student in sorted_by_grade:
print(f" {student['name']}: {student['grade']}")
# 按姓名排序
sorted_by_name = sorted(students, key=lambda student: student["name"])
print("\n按姓名排序:")
for student in sorted_by_name:
print(f" {student['name']}: {student['grade']}")
3. lambda的实际应用
# 数据处理
data = [
{"product": "笔记本电脑", "price": 5000, "quantity": 2},
{"product": "鼠标", "price": 50, "quantity": 10},
{"product": "键盘", "price": 200, "quantity": 5},
{"product": "显示器", "price": 1500, "quantity": 3}
]
# 计算总价值
total_values = list(map(lambda item: item["price"] * item["quantity"], data))
print(f"各商品总价值: {total_values}")
# 筛选高价值商品(总价值>1000)
high_value_items = list(filter(lambda item: item["price"] * item["quantity"] > 1000, data))
print("\n高价值商品:")
for item in high_value_items:
total_value = item["price"] * item["quantity"]
print(f" {item['product']}: ¥{total_value}")
# 按总价值排序
sorted_by_value = sorted(data, key=lambda item: item["price"] * item["quantity"], reverse=True)
print("\n按总价值排序:")
for item in sorted_by_value:
total_value = item["price"] * item["quantity"]
print(f" {item['product']}: ¥{total_value}")
4. lambda的限制和替代方案
# ❌ lambda的限制:只能包含表达式,不能包含语句
# 不能使用print、赋值等语句
# bad_lambda = lambda x: print(x) # 语法错误
# ✅ 对于复杂逻辑,使用普通函数
def process_grade(score):
"""处理成绩,包含复杂逻辑"""
if score >= 90:
grade = "A"
message = "优秀"
elif score >= 80:
grade = "B"
message = "良好"
elif score >= 70:
grade = "C"
message = "中等"
elif score >= 60:
grade = "D"
message = "及格"
else:
grade = "F"
message = "不及格"
return {"grade": grade, "message": message}
# 使用普通函数处理复杂逻辑
scores = [95, 87, 72, 58, 91]
processed_scores = list(map(process_grade, scores))
for i, result in enumerate(processed_scores):
print(f"分数{scores[i]}: {result['grade']} - {result['message']}")
# ✅ lambda适用场景:简单的数据转换
temperatures_celsius = [0, 20, 30, 40]
temperatures_fahrenheit = list(map(lambda c: c * 9/5 + 32, temperatures_celsius))
print(f"\n摄氏度: {temperatures_celsius}")
print(f"华氏度: {temperatures_fahrenheit}")
函数的作用域
作用域决定了变量在程序中的可见性和生命周期。
1. 全局作用域与局部作用域
# 全局变量
global_var = "我是全局变量"
counter = 0
def demo_scope():
# 局部变量
local_var = "我是局部变量"
print(f"函数内部访问全局变量: {global_var}")
print(f"函数内部访问局部变量: {local_var}")
demo_scope()
print(f"函数外部访问全局变量: {global_var}")
# print(local_var) # 错误:局部变量在函数外部不可见
# 变量遮蔽(Shadowing)
name = "全局名称"
def shadow_demo():
name = "局部名称" # 遮蔽全局变量
print(f"函数内部的name: {name}")
shadow_demo()
print(f"函数外部的name: {name}")
2. global关键字
counter = 0 # 全局计数器
def increment_counter():
global counter # 声明使用全局变量
counter += 1
print(f"计数器值: {counter}")
def reset_counter():
global counter
counter = 0
print("计数器已重置")
# 测试全局变量修改
print(f"初始计数器: {counter}")
increment_counter()
increment_counter()
increment_counter()
reset_counter()
print(f"最终计数器: {counter}")
# 实际应用:配置管理
config = {
"debug": False,
"max_connections": 100,
"timeout": 30
}
def set_debug_mode(enabled):
global config
config["debug"] = enabled
print(f"调试模式: {'开启' if enabled else '关闭'}")
def get_config(key):
return config.get(key)
set_debug_mode(True)
print(f"最大连接数: {get_config('max_connections')}")
3. nonlocal关键字
def outer_function():
x = "外层函数变量"
def inner_function():
nonlocal x # 声明使用外层函数的变量
x = "被内层函数修改"
print(f"内层函数中的x: {x}")
print(f"调用内层函数前: {x}")
inner_function()
print(f"调用内层函数后: {x}")
outer_function()
# 实际应用:创建计数器函数
def create_counter(initial_value=0):
count = initial_value
def increment(step=1):
nonlocal count
count += step
return count
def decrement(step=1):
nonlocal count
count -= step
return count
def get_count():
return count
def reset():
nonlocal count
count = initial_value
return count
# 返回函数字典
return {
"increment": increment,
"decrement": decrement,
"get": get_count,
"reset": reset
}
# 使用计数器
counter1 = create_counter(10)
counter2 = create_counter()
print(f"counter1初始值: {counter1['get']()}")
print(f"counter2初始值: {counter2['get']()}")
print(f"counter1增加5: {counter1['increment'](5)}")
print(f"counter2增加1: {counter2['increment']()}")
print(f"counter1减少3: {counter1['decrement'](3)}")
print(f"counter2当前值: {counter2['get']()}")
counter1['reset']()
print(f"counter1重置后: {counter1['get']()}")
4. LEGB规则
Python使用LEGB规则来解析变量名:Local → Enclosing → Global → Built-in
# Built-in作用域
print(f"内置函数len: {len}")
print(f"内置函数max: {max}")
# Global作用域
len = "全局变量len" # 遮蔽内置函数
max_value = 100
def outer():
# Enclosing作用域
len = "外层函数len" # 遮蔽全局变量
max_value = 50
def inner():
# Local作用域
len = "内层函数len" # 遮蔽外层变量
print(f"Local len: {len}")
print(f"Enclosing max_value: {max_value}")
print(f"Global len: {globals()['len']}")
print(f"Built-in len: {__builtins__['len']}")
inner()
print(f"Enclosing len: {len}")
outer()
print(f"Global len: {len}")
# 恢复内置函数
del len # 删除全局变量len
print(f"恢复后的len函数: {len([1, 2, 3])}")
模块的导入(import)
模块是包含Python代码的文件,可以定义函数、类和变量,也可以包含可执行代码。
1. 基本导入方式
# 导入整个模块
import math
print(f"π的值: {math.pi}")
print(f"10的平方根: {math.sqrt(10)}")
print(f"sin(π/2): {math.sin(math.pi/2)}")
# 导入特定函数或变量
from math import pi, sqrt, sin, cos
print(f"π的值: {pi}")
print(f"10的平方根: {sqrt(10)}")
print(f"sin(π/2): {sin(pi/2)}")
print(f"cos(0): {cos(0)}")
# 使用别名
import math as m
from math import sqrt as square_root
print(f"使用别名访问π: {m.pi}")
print(f"使用别名计算平方根: {square_root(16)}")
# 导入所有内容(不推荐)
# from math import *
# print(f"直接使用函数名: {sqrt(25)}")
2. 常用标准库模块
# datetime模块 - 日期时间处理
from datetime import datetime, date, timedelta
now = datetime.now()
today = date.today()
tomorrow = today + timedelta(days=1)
print(f"当前时间: {now}")
print(f"今天日期: {today}")
print(f"明天日期: {tomorrow}")
print(f"格式化时间: {now.strftime('%Y-%m-%d %H:%M:%S')}")
# random模块 - 随机数生成
import random
print(f"随机整数(1-10): {random.randint(1, 10)}")
print(f"随机浮点数(0-1): {random.random()}")
print(f"随机选择: {random.choice(['苹果', '香蕉', '橙子'])}")
# 随机打乱列表
numbers = [1, 2, 3, 4, 5]
random.shuffle(numbers)
print(f"打乱后的列表: {numbers}")
# os模块 - 操作系统接口
import os
print(f"当前工作目录: {os.getcwd()}")
print(f"用户主目录: {os.path.expanduser('~')}")
print(f"路径分隔符: {os.path.sep}")
# 环境变量
print(f"PATH环境变量: {os.environ.get('PATH', '未设置')[:100]}...")
# sys模块 - 系统相关参数和函数
import sys
print(f"Python版本: {sys.version}")
print(f"平台信息: {sys.platform}")
print(f"模块搜索路径: {sys.path[:3]}...") # 只显示前3个路径
3. 模块搜索路径
import sys
print("Python模块搜索路径:")
for i, path in enumerate(sys.path, 1):
print(f"{i:2d}. {path}")
# 添加自定义路径
custom_path = "/path/to/my/modules"
if custom_path not in sys.path:
sys.path.append(custom_path)
print(f"\n已添加自定义路径: {custom_path}")
# 查看模块的位置
import math
print(f"\nmath模块位置: {math.__file__}")
# 查看模块的所有属性
print(f"\nmath模块的部分属性: {[attr for attr in dir(math) if not attr.startswith('_')][:10]}")
Python标准库
Python拥有丰富的标准库,提供了大量实用的模块。
1. 文件和路径操作
# pathlib模块 - 现代路径操作(推荐)
from pathlib import Path
# 创建路径对象
current_dir = Path.cwd()
home_dir = Path.home()
file_path = current_dir / "example.txt"
print(f"当前目录: {current_dir}")
print(f"用户主目录: {home_dir}")
print(f"文件路径: {file_path}")
# 路径操作
print(f"文件名: {file_path.name}")
print(f"文件扩展名: {file_path.suffix}")
print(f"父目录: {file_path.parent}")
print(f"是否存在: {file_path.exists()}")
print(f"是否为文件: {file_path.is_file()}")
print(f"是否为目录: {file_path.is_dir()}")
# 创建目录
test_dir = current_dir / "test_directory"
test_dir.mkdir(exist_ok=True) # exist_ok=True表示目录存在时不报错
print(f"创建目录: {test_dir}")
# 遍历目录
print("\n当前目录下的Python文件:")
for py_file in current_dir.glob("*.py"):
print(f" {py_file.name}")
2. 数据序列化
# json模块 - JSON数据处理
import json
# Python对象转JSON
data = {
"name": "张三",
"age": 25,
"hobbies": ["读书", "游泳", "编程"],
"is_student": True,
"address": {
"city": "北京",
"district": "朝阳区"
}
}
# 转换为JSON字符串
json_string = json.dumps(data, ensure_ascii=False, indent=2)
print("JSON字符串:")
print(json_string)
# JSON字符串转Python对象
parsed_data = json.loads(json_string)
print(f"\n解析后的数据: {parsed_data}")
print(f"姓名: {parsed_data['name']}")
print(f"爱好: {', '.join(parsed_data['hobbies'])}")
# 文件操作
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print("\n数据已保存到data.json")
with open("data.json", "r", encoding="utf-8") as f:
loaded_data = json.load(f)
print(f"从文件加载的数据: {loaded_data['name']}")
3. 正则表达式
# re模块 - 正则表达式
import re
# 基本匹配
text = "我的电话是138-0013-8000,邮箱是user@example.com"
# 查找电话号码
phone_pattern = r'\d{3}-\d{4}-\d{4}'
phone_match = re.search(phone_pattern, text)
if phone_match:
print(f"找到电话号码: {phone_match.group()}")
# 查找邮箱
email_pattern = r'\w+@\w+\.\w+'
email_match = re.search(email_pattern, text)
if email_match:
print(f"找到邮箱: {email_match.group()}")
# 查找所有匹配
text_with_numbers = "今天的温度是25度,明天是28度,后天是30度"
number_pattern = r'\d+'
numbers = re.findall(number_pattern, text_with_numbers)
print(f"找到的所有数字: {numbers}")
# 替换操作
original = "Hello World! Hello Python!"
replaced = re.sub(r'Hello', 'Hi', original)
print(f"替换后: {replaced}")
# 分割字符串
data = "apple,banana;orange:grape"
fruits = re.split(r'[,;:]', data)
print(f"分割后的水果: {fruits}")
# 编译正则表达式(提高性能)
email_regex = re.compile(r'([\w\.-]+)@([\w\.-]+)\.([\w]+)')
emails = [
"user@example.com",
"admin@company.org",
"invalid-email",
"test@domain.net"
]
print("\n邮箱验证结果:")
for email in emails:
match = email_regex.match(email)
if match:
username, domain, tld = match.groups()
print(f" {email}: 有效 (用户名: {username}, 域名: {domain}, 顶级域: {tld})")
else:
print(f" {email}: 无效")
4. 集合和计数器
# collections模块 - 特殊容器数据类型
from collections import Counter, defaultdict, namedtuple, deque
# Counter - 计数器
text = "hello world"
letter_count = Counter(text)
print(f"字母计数: {letter_count}")
print(f"最常见的3个字母: {letter_count.most_common(3)}")
# 统计单词频率
words = "python is great python is powerful python is easy".split()
word_count = Counter(words)
print(f"单词计数: {word_count}")
# defaultdict - 带默认值的字典
student_grades = defaultdict(list)
student_grades["张三"].append(85)
student_grades["张三"].append(92)
student_grades["李四"].append(78)
print(f"学生成绩: {dict(student_grades)}")
# namedtuple - 命名元组
Point = namedtuple('Point', ['x', 'y'])
Student = namedtuple('Student', ['name', 'age', 'grade'])
p1 = Point(3, 4)
s1 = Student("Alice", 20, "A")
print(f"点坐标: ({p1.x}, {p1.y})")
print(f"学生信息: {s1.name}, {s1.age}岁, 成绩{s1.grade}")
# deque - 双端队列
queue = deque([1, 2, 3])
queue.appendleft(0) # 左侧添加
queue.append(4) # 右侧添加
print(f"双端队列: {list(queue)}")
left_item = queue.popleft() # 左侧弹出
right_item = queue.pop() # 右侧弹出
print(f"弹出的元素: 左={left_item}, 右={right_item}")
print(f"剩余队列: {list(queue)}")
自定义模块的创建与使用
1. 创建自定义模块
# 创建一个名为 math_utils.py 的模块文件
# 以下代码应该保存在单独的文件中
"""
math_utils.py - 数学工具模块
这个模块提供了一些常用的数学计算函数。
"""
import math
# 模块级别的常量
PI = 3.14159265359
E = 2.71828182846
# 模块级别的变量
_calculation_count = 0 # 私有变量(约定)
def factorial(n):
"""
计算阶乘
Args:
n (int): 非负整数
Returns:
int: n的阶乘
Raises:
ValueError: 当n为负数时
"""
global _calculation_count
_calculation_count += 1
if n < 0:
raise ValueError("阶乘的参数必须是非负整数")
if n == 0 or n == 1:
return 1
result = 1
for i in range(2, n + 1):
result *= i
return result
def is_prime(n):
"""
判断是否为质数
Args:
n (int): 要判断的数字
Returns:
bool: 如果是质数返回True,否则返回False
"""
global _calculation_count
_calculation_count += 1
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
for i in range(3, int(math.sqrt(n)) + 1, 2):
if n % i == 0:
return False
return True
def gcd(a, b):
"""
计算最大公约数(欧几里得算法)
Args:
a (int): 第一个数
b (int): 第二个数
Returns:
int: 最大公约数
"""
global _calculation_count
_calculation_count += 1
while b:
a, b = b, a % b
return abs(a)
def lcm(a, b):
"""
计算最小公倍数
Args:
a (int): 第一个数
b (int): 第二个数
Returns:
int: 最小公倍数
"""
return abs(a * b) // gcd(a, b)
def get_calculation_count():
"""
获取计算次数
Returns:
int: 模块中函数被调用的总次数
"""
return _calculation_count
def reset_calculation_count():
"""
重置计算次数
"""
global _calculation_count
_calculation_count = 0
# 模块初始化代码
print(f"math_utils模块已加载,版本: 1.0")
# 当模块被直接运行时执行的代码
if __name__ == "__main__":
print("math_utils模块测试:")
print(f"5的阶乘: {factorial(5)}")
print(f"17是质数: {is_prime(17)}")
print(f"12和18的最大公约数: {gcd(12, 18)}")
print(f"12和18的最小公倍数: {lcm(12, 18)}")
print(f"计算次数: {get_calculation_count()}")
2. 使用自定义模块
# 假设math_utils.py已经创建,现在使用它
# 方式1: 导入整个模块
import math_utils
print(f"π的值: {math_utils.PI}")
print(f"6的阶乘: {math_utils.factorial(6)}")
print(f"29是质数: {math_utils.is_prime(29)}")
print(f"计算次数: {math_utils.get_calculation_count()}")
# 方式2: 导入特定函数
from math_utils import factorial, is_prime, gcd, lcm
print(f"\n7的阶乘: {factorial(7)}")
print(f"31是质数: {is_prime(31)}")
print(f"24和36的最大公约数: {gcd(24, 36)}")
print(f"24和36的最小公倍数: {lcm(24, 36)}")
# 方式3: 使用别名
import math_utils as mu
print(f"\n使用别名计算8的阶乘: {mu.factorial(8)}")
print(f"当前计算次数: {mu.get_calculation_count()}")
# 重置计数器
mu.reset_calculation_count()
print(f"重置后计算次数: {mu.get_calculation_count()}")
3. 包(Package)的创建
# 创建包结构
# mypackage/
# ├── __init__.py
# ├── math_utils.py
# ├── string_utils.py
# └── data_utils.py
# __init__.py 文件内容
"""
mypackage包的初始化文件
这个包提供了数学、字符串和数据处理的工具函数。
"""
# 包的版本信息
__version__ = "1.0.0"
__author__ = "Your Name"
__email__ = "your.email@example.com"
# 导入子模块的重要函数,使其在包级别可用
from .math_utils import factorial, is_prime, gcd, lcm
from .string_utils import reverse_string, count_words
from .data_utils import find_max, find_min, calculate_average
# 定义__all__列表,控制from mypackage import *的行为
__all__ = [
'factorial', 'is_prime', 'gcd', 'lcm',
'reverse_string', 'count_words',
'find_max', 'find_min', 'calculate_average'
]
print(f"mypackage v{__version__} 已加载")
# string_utils.py 文件内容
"""
string_utils.py - 字符串工具模块
"""
def reverse_string(s):
"""反转字符串"""
return s[::-1]
def count_words(text):
"""统计单词数量"""
return len(text.split())
def capitalize_words(text):
"""将每个单词的首字母大写"""
return ' '.join(word.capitalize() for word in text.split())
# data_utils.py 文件内容
"""
data_utils.py - 数据处理工具模块
"""
def find_max(data):
"""找到列表中的最大值"""
if not data:
return None
return max(data)
def find_min(data):
"""找到列表中的最小值"""
if not data:
return None
return min(data)
def calculate_average(data):
"""计算平均值"""
if not data:
return None
return sum(data) / len(data)
def filter_positive(data):
"""过滤出正数"""
return [x for x in data if x > 0]
4. 使用包
# 使用自定义包
# 方式1: 导入整个包
import mypackage
print(f"包版本: {mypackage.__version__}")
print(f"5的阶乘: {mypackage.factorial(5)}")
print(f"反转字符串: {mypackage.reverse_string('hello')}")
# 方式2: 导入特定模块
from mypackage import math_utils, string_utils
print(f"13是质数: {math_utils.is_prime(13)}")
print(f"单词数量: {string_utils.count_words('Hello Python World')}")
# 方式3: 导入特定函数
from mypackage.data_utils import find_max, calculate_average
data = [1, 5, 3, 9, 2, 7]
print(f"最大值: {find_max(data)}")
print(f"平均值: {calculate_average(data):.2f}")
# 方式4: 使用__all__定义的内容
from mypackage import *
print(f"最大公约数: {gcd(48, 18)}")
print(f"字符串处理: {reverse_string('Python')}")
实际项目示例
创建一个简单的学生管理系统
# student_manager.py - 学生管理系统模块
"""
学生管理系统
功能:
- 添加学生
- 删除学生
- 查找学生
- 计算平均分
- 生成报告
"""
import json
from datetime import datetime
from pathlib import Path
class StudentManager:
"""学生管理器类"""
def __init__(self, data_file="students.json"):
self.data_file = Path(data_file)
self.students = self._load_data()
def _load_data(self):
"""从文件加载学生数据"""
if self.data_file.exists():
try:
with open(self.data_file, 'r', encoding='utf-8') as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
print("数据文件损坏,创建新的数据文件")
return {}
return {}
def _save_data(self):
"""保存学生数据到文件"""
try:
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump(self.students, f, ensure_ascii=False, indent=2)
return True
except IOError as e:
print(f"保存数据失败: {e}")
return False
def add_student(self, student_id, name, age, grades=None):
"""添加学生"""
if student_id in self.students:
print(f"学生ID {student_id} 已存在")
return False
self.students[student_id] = {
"name": name,
"age": age,
"grades": grades or [],
"created_at": datetime.now().isoformat()
}
if self._save_data():
print(f"学生 {name} 添加成功")
return True
return False
def remove_student(self, student_id):
"""删除学生"""
if student_id not in self.students:
print(f"学生ID {student_id} 不存在")
return False
student_name = self.students[student_id]["name"]
del self.students[student_id]
if self._save_data():
print(f"学生 {student_name} 删除成功")
return True
return False
def find_student(self, student_id):
"""查找学生"""
return self.students.get(student_id)
def add_grade(self, student_id, subject, score):
"""添加成绩"""
if student_id not in self.students:
print(f"学生ID {student_id} 不存在")
return False
grade_entry = {
"subject": subject,
"score": score,
"date": datetime.now().isoformat()
}
self.students[student_id]["grades"].append(grade_entry)
if self._save_data():
print(f"为学生 {self.students[student_id]['name']} 添加 {subject} 成绩: {score}")
return True
return False
def calculate_average(self, student_id):
"""计算学生平均分"""
student = self.find_student(student_id)
if not student:
return None
grades = student["grades"]
if not grades:
return None
total_score = sum(grade["score"] for grade in grades)
return total_score / len(grades)
def get_all_students(self):
"""获取所有学生信息"""
return self.students
def generate_report(self):
"""生成学生报告"""
if not self.students:
print("没有学生数据")
return
print("\n=== 学生管理系统报告 ===")
print(f"总学生数: {len(self.students)}")
print(f"报告生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("\n学生详细信息:")
for student_id, info in self.students.items():
print(f"\nID: {student_id}")
print(f"姓名: {info['name']}")
print(f"年龄: {info['age']}")
print(f"成绩数量: {len(info['grades'])}")
if info['grades']:
avg_score = self.calculate_average(student_id)
print(f"平均分: {avg_score:.2f}")
print("各科成绩:")
for grade in info['grades']:
print(f" {grade['subject']}: {grade['score']}")
else:
print("暂无成绩记录")
# 使用示例
def main():
"""主函数演示学生管理系统的使用"""
# 创建学生管理器
manager = StudentManager()
# 添加学生
manager.add_student("001", "张三", 20)
manager.add_student("002", "李四", 19)
manager.add_student("003", "王五", 21)
# 添加成绩
manager.add_grade("001", "数学", 85)
manager.add_grade("001", "英语", 92)
manager.add_grade("001", "物理", 78)
manager.add_grade("002", "数学", 90)
manager.add_grade("002", "英语", 88)
manager.add_grade("003", "数学", 95)
manager.add_grade("003", "英语", 89)
manager.add_grade("003", "物理", 92)
# 查找学生
student = manager.find_student("001")
if student:
print(f"\n找到学生: {student['name']}")
avg = manager.calculate_average("001")
print(f"平均分: {avg:.2f}")
# 生成报告
manager.generate_report()
if __name__ == "__main__":
main()
总结
函数与模块是Python编程的核心概念:
函数的优势
- 代码重用: 避免重复编写相同的代码
- 模块化: 将复杂问题分解为小的、可管理的部分
- 可测试性: 独立的函数更容易测试和调试
- 可读性: 良好命名的函数提高代码可读性
模块的优势
- 命名空间: 避免命名冲突
- 代码组织: 将相关功能组织在一起
- 可维护性: 便于代码的维护和更新
- 可扩展性: 支持大型项目的开发
最佳实践
- 函数设计: 遵循单一职责原则,函数应该只做一件事
- 参数设计: 合理使用各种参数类型,避免参数过多
- 文档字符串: 为函数和模块编写清晰的文档
- 错误处理: 适当处理异常情况
- 模块组织: 合理组织模块结构,使用包来管理复杂项目
通过掌握函数与模块,你可以编写更加结构化、可维护和可重用的Python代码。