python基础-函数与模块

75 阅读24分钟

函数与模块

函数是组织代码的基本单位,它将相关的代码组织在一起,实现特定的功能。模块则是更高层次的代码组织方式,可以包含多个函数、类和变量。

代码组织层次图:
┌─────────────────────────────────────────────┐
│              代码组织结构                   │
├─────────────────────────────────────────────┤
│                                             │
│  语句 → 函数 → 模块 → 包 → 项目            │
│   │      │      │      │      │             │
│   ▼      ▼      ▼      ▼      ▼             │
│  基本   代码   文件   目录   完整            │
│  操作   块     .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编程的核心概念:

函数的优势

  • 代码重用: 避免重复编写相同的代码
  • 模块化: 将复杂问题分解为小的、可管理的部分
  • 可测试性: 独立的函数更容易测试和调试
  • 可读性: 良好命名的函数提高代码可读性

模块的优势

  • 命名空间: 避免命名冲突
  • 代码组织: 将相关功能组织在一起
  • 可维护性: 便于代码的维护和更新
  • 可扩展性: 支持大型项目的开发

最佳实践

  1. 函数设计: 遵循单一职责原则,函数应该只做一件事
  2. 参数设计: 合理使用各种参数类型,避免参数过多
  3. 文档字符串: 为函数和模块编写清晰的文档
  4. 错误处理: 适当处理异常情况
  5. 模块组织: 合理组织模块结构,使用包来管理复杂项目

通过掌握函数与模块,你可以编写更加结构化、可维护和可重用的Python代码。

更多精彩文章

搜索框传播样式-白色版.png