当前位置: 首页 > news >正文

第十一章:AI进阶之--模块的概念与使用(二)

请添加图片描述
在这里插入图片描述


文章目录

    • 五、模块的搜索路径
      • 5.1 查看模块搜索路径
      • 5.2 模块搜索顺序
      • 5.3 添加自定义模块路径
      • 5.4 避免模块命名冲突
    • 六、创建和使用自定义模块
      • 6.1 创建自定义模块
      • 6.2 使用自定义模块
      • 6.3 模块中的主程序代码
      • 6.4 模块中的私有成员
    • 七、模块使用的常见问题与解决方案(10分钟)
      • 7.1 模块找不到错误(ModuleNotFoundError)
      • 7.2 导入模块后函数/变量不存在(AttributeError)
      • 7.3 循环导入问题
      • 7.4 模块重新加载问题
    • 八、实战练习(15分钟)
      • 8.1 练习1:使用math模块计算圆的周长和面积
      • 8.3 练习3:创建和使用自定义模块
    • 九、课程总结


五、模块的搜索路径

当我们导入一个模块时,Python解释器会按照一定的路径顺序查找该模块。了解模块的搜索路径有助于我们理解为什么有时会出现ModuleNotFoundError错误。

5.1 查看模块搜索路径

可以通过sys模块的path变量查看Python的模块搜索路径:

import sysprint("模块搜索路径:")
for path in sys.path:print(path)

运行结果通常包括以下几类路径:

  1. 当前执行脚本所在的目录
  2. Python的安装目录(标准库模块所在的目录)
  3. 第三方库安装目录(如site-packages
  4. 通过环境变量PYTHONPATH指定的目录

5.2 模块搜索顺序

当导入一个模块时,Python解释器按照以下顺序搜索模块:

  1. 首先搜索内置模块(如mathrandom等)
  2. 然后按照sys.path列表中的路径顺序进行搜索
  3. 如果找到模块,则导入;如果遍历所有路径都找不到,则抛出ModuleNotFoundError异常

5.3 添加自定义模块路径

如果我们的自定义模块不在Python的默认搜索路径中,可以通过以下方法添加路径:

  1. 临时添加:在程序中修改sys.path,仅在当前程序运行时有效:
import sys
import os# 获取自定义模块所在的目录
module_dir = os.path.abspath("path/to/your/modules")# 添加到搜索路径
if module_dir not in sys.path:sys.path.append(module_dir)# 现在可以导入该目录下的模块了
import your_module
  1. 永久添加
    • 将模块所在目录添加到环境变量PYTHONPATH
    • 在Python的site-packages目录下创建一个.pth文件,文件中写入模块所在目录的路径

5.4 避免模块命名冲突

当我们的自定义模块与Python标准库模块或第三方库模块同名时,会导致命名冲突。例如,如果我们创建了一个math.py文件,那么当我们使用import math时,导入的将是我们自己的math.py文件,而不是标准库的math模块。

避免命名冲突的方法

  1. 避免使用与标准库模块同名的文件名
  2. 使用包(package)来组织模块,通过包名来区分
  3. 导入时使用别名机制

六、创建和使用自定义模块

除了使用Python提供的内置模块和第三方模块外,我们还可以创建自己的模块来组织代码。

6.1 创建自定义模块

创建自定义模块非常简单,只需要创建一个.py文件,在文件中定义函数、类和变量即可。

示例:创建一个名为string_utils.py的模块,包含一些字符串处理函数:

# string_utils.py
"""字符串处理工具模块"""def reverse_string(s):"""反转字符串"""return s[::-1]def capitalize_words(s):"""将字符串中每个单词的首字母大写"""return ' '.join(word.capitalize() for word in s.split())def is_palindrome(s):"""判断字符串是否为回文(忽略大小写和非字母字符)"""# 过滤非字母字符并转换为小写filtered = ''.join(c.lower() for c in s if c.isalpha())return filtered == filtered[::-1]# 模块级变量
MODULE_VERSION = "1.0"

6.2 使用自定义模块

创建好自定义模块后,就可以在其他程序中导入并使用它了。

示例:在另一个Python文件中使用string_utils模块:

# main.py
import string_utils# 使用模块中的函数
original = "hello world"
reversed_str = string_utils.reverse_string(original)
print(f"原始字符串: {original}")
print(f"反转字符串: {reversed_str}")sentence = "hello world, welcome to python"
capitalized = string_utils.capitalize_words(sentence)
print(f"原始句子: {sentence}")
print(f"首字母大写: {capitalized}")test_str1 = "A man a plan a canal Panama"
test_str2 = "Hello World"
print(f"'{test_str1}' 是回文吗? {string_utils.is_palindrome(test_str1)}")  # 输出: True
print(f"'{test_str2}' 是回文吗? {string_utils.is_palindrome(test_str2)}")  # 输出: False# 使用模块中的变量
print(f"模块版本: {string_utils.MODULE_VERSION}")

6.3 模块中的主程序代码

有时,我们希望模块既可以被其他程序导入,又可以作为独立的脚本运行(例如用于测试模块功能)。这时可以使用if __name__ == "__main__":语句。

当模块被导入时,__name__变量的值是模块名;当模块作为独立脚本运行时,__name__变量的值是"__main__"

示例:为string_utils.py模块添加测试代码:

# string_utils.py(添加测试代码后)
"""字符串处理工具模块"""def reverse_string(s):"""反转字符串"""return s[::-1]def capitalize_words(s):"""将字符串中每个单词的首字母大写"""return ' '.join(word.capitalize() for word in s.split())def is_palindrome(s):"""判断字符串是否为回文(忽略大小写和非字母字符)"""# 过滤非字母字符并转换为小写filtered = ''.join(c.lower() for c in s if c.isalpha())return filtered == filtered[::-1]# 模块级变量
MODULE_VERSION = "1.0"# 当模块作为独立脚本运行时执行的代码
if __name__ == "__main__":print("测试 reverse_string 函数:")print(reverse_string("hello") == "olleh")  # 输出: Trueprint("\n测试 capitalize_words 函数:")print(capitalize_words("hello world") == "Hello World")  # 输出: Trueprint("\n测试 is_palindrome 函数:")print(is_palindrome("A man a plan a canal Panama"))  # 输出: Trueprint(is_palindrome("Hello World"))  # 输出: False

现在,当我们直接运行string_utils.py时,会执行测试代码;当其他程序导入string_utils模块时,测试代码不会被执行。

6.4 模块中的私有成员

在模块中,以下划线_开头的函数、类或变量被视为私有成员,按照惯例不应该被外部访问。

示例:在模块中定义私有函数:

# utils.py
def public_function():"""公共函数,可以被外部访问"""print("这是一个公共函数")_private_function()  # 模块内部可以访问私有函数def _private_function():"""私有函数,按照惯例不应该被外部访问"""print("这是一个私有函数")public_variable = "这是一个公共变量"
_private_variable = "这是一个私有变量"

当其他程序导入这个模块时,虽然技术上可以访问私有成员,但按照Python的惯例,不应该这样做:

import utilsutils.public_function()  # 正确:调用公共函数
# 输出:
# 这是一个公共函数
# 这是一个私有函数# 不推荐:访问私有函数和变量(虽然技术上可行)
utils._private_function()
print(utils._private_variable)

使用from module import *导入模块时,私有成员不会被导入:

from utils import *public_function()  # 可以访问
# _private_function()  # 错误:NameError: name '_private_function' is not defined

七、模块使用的常见问题与解决方案(10分钟)

7.1 模块找不到错误(ModuleNotFoundError)

错误表现

ModuleNotFoundError: No module named 'module_name'

常见原因与解决方案

  1. 模块名拼写错误

    • 检查模块名的拼写是否正确,Python对大小写敏感。
  2. 模块不在搜索路径中

    • 检查模块所在目录是否在sys.path中。
    • 将模块所在目录添加到sys.path中。
  3. 模块文件扩展名错误

    • 确保模块文件以.py为扩展名。
  4. 循环导入

    • 避免模块A导入模块B,同时模块B又导入模块A的情况。
  5. 命名冲突

    • 检查是否有与模块同名的文件或目录。

7.2 导入模块后函数/变量不存在(AttributeError)

错误表现

AttributeError: module 'module_name' has no attribute 'function_name'

常见原因与解决方案

  1. 函数/变量名拼写错误

    • 检查函数名或变量名的拼写是否正确。
  2. 函数/变量确实不存在于模块中

    • 检查模块中是否定义了该函数或变量。
  3. 导入的是目录而不是模块

    • 确保导入的是.py文件,而不是同名的目录。
  4. 使用from module import *时未导入私有成员

    • 以下划线_开头的私有成员不会被from module import *导入。

7.3 循环导入问题

错误表现

ImportError: cannot import name 'function_name' from partially initialized module 'module_name'

常见原因

当模块A导入模块B,同时模块B又导入模块A时,会导致循环导入问题。

示例

# a.py
from b import b_functiondef a_function():print("This is a_function")b_function()
# b.py
from a import a_functiondef b_function():print("This is b_function")a_function()

解决方案

  1. 重构代码:将两个模块共同依赖的部分提取到第三个模块中。
  2. 延迟导入:在函数内部而不是模块顶部导入。
  3. 调整导入顺序:将导入语句放在模块的末尾。

使用延迟导入解决循环导入

# a.py
def a_function():from b import b_function  # 延迟导入print("This is a_function")b_function()
# b.py
def b_function():from a import a_function  # 延迟导入print("This is b_function")a_function()

7.4 模块重新加载问题

当我们修改了模块代码后,已经运行的程序不会自动加载更新后的模块。

解决方案

使用importlib模块的reload函数重新加载模块:

import importlib
import my_module  # 第一次导入# 修改了my_module.py文件后
importlib.reload(my_module)  # 重新加载模块

注意

  • 重新加载模块会保留模块的原有全局变量
  • 重新加载模块可能导致一些不可预期的问题,建议在开发环境中使用
  • 在生产环境中,通常通过重启程序来加载更新后的模块

八、实战练习(15分钟)

8.1 练习1:使用math模块计算圆的周长和面积

编写一个程序,使用math模块计算圆的周长和面积。程序应提示用户输入圆的半径,然后计算并输出结果。

示例代码

import mathdef calculate_circle_properties(radius):"""计算圆的周长和面积"""circumference = 2 * math.pi * radiusarea = math.pi * math.pow(radius, 2)return circumference, areaif __name__ == "__main__":try:radius = float(input("请输入圆的半径:"))if radius <= 0:print("错误:半径必须是正数")else:circumference, area = calculate_circle_properties(radius)print(f"半径为{radius}的圆:")print(f"周长:{circumference:.2f}")print(f"面积:{area:.2f}")except ValueError:print("错误:请输入有效的数字")

预期输出

请输入圆的半径:5
半径为5.0的圆:
周长:31.42
面积:78.54

8.3 练习3:创建和使用自定义模块

创建一个名为statistics_utils.py的模块,包含以下函数:

  • mean(numbers):计算列表中数字的平均值
  • median(numbers):计算列表中数字的中位数
  • mode(numbers):计算列表中数字的众数
  • standard_deviation(numbers):计算列表中数字的标准差

然后创建一个main.py文件,导入并使用这个模块,测试这些函数的功能。

statistics_utils.py代码

# statistics_utils.py
import mathdef mean(numbers):"""计算平均值"""if not numbers:raise ValueError("列表不能为空")return sum(numbers) / len(numbers)def median(numbers):"""计算中位数"""if not numbers:raise ValueError("列表不能为空")sorted_numbers = sorted(numbers)n = len(sorted_numbers)mid = n // 2if n % 2 == 1:return sorted_numbers[mid]else:return (sorted_numbers[mid-1] + sorted_numbers[mid]) / 2def mode(numbers):"""计算众数(出现次数最多的数)"""if not numbers:raise ValueError("列表不能为空")frequency = {}for num in numbers:frequency[num] = frequency.get(num, 0) + 1max_freq = max(frequency.values())modes = [num for num, freq in frequency.items() if freq == max_freq]return modes if len(modes) > 1 else modes[0]def standard_deviation(numbers):"""计算标准差"""if not numbers:raise ValueError("列表不能为空")avg = mean(numbers)squared_diff = [(num - avg) **2 for num in numbers]variance = mean(squared_diff)return math.sqrt(variance)# 测试代码
if __name__ == "__main__":test_data = [1, 2, 3, 4, 5, 5, 6, 7, 8, 9]print("测试数据:", test_data)print("平均值:", mean(test_data))print("中位数:", median(test_data))print("众数:", mode(test_data))print("标准差:", standard_deviation(test_data))

main.py代码

# main.py
import statistics_utils as statsdef main():data = [2, 4, 4, 4, 5, 5, 7, 9]print("数据:", data)print(f"平均值: {stats.mean(data):.2f}")print(f"中位数: {stats.median(data)}")print(f"众数: {stats.mode(data)}")print(f"标准差: {stats.standard_deviation(data):.2f}")if __name__ == "__main__":main()

预期输出

数据: [2, 4, 4, 4, 5, 5, 7, 9]
平均值: 5.00
中位数: 4.5
众数: 4
标准差: 2.13

九、课程总结

在本节课中,我们学习了Python模块的概念与使用,这是Python编程中组织和管理代码的重要工具。通过本节课的学习,你应该能够:

重点回顾

1.** 模块的概念与作用 **:

  • 模块是包含Python代码的.py文件,用于组织相关的函数、类和变量。
  • 模块的主要作用是代码组织、功能复用、命名空间隔离等。

2.** 导入模块的方法 **:

  • import 模块名:导入整个模块,通过模块名访问其内容。
  • from 模块名 import 函数/变量:导入模块中的指定内容,可直接访问。
  • from 模块名 import *:导入模块中的所有内容(不推荐)。
  • import 模块名 as 别名:为模块指定别名,简化使用。
  • from 模块名 import 函数名 as 别名:为函数指定别名,解决冲突。

3.** 常用内置模块 **:

  • math模块:提供数学运算功能,如sqrt()pi等。
  • random模块:提供随机数生成功能,如randint()choice()等。
  • datetime模块:提供日期和时间处理功能。

4.** 模块的搜索路径 **:

  • Python按照sys.path中的路径顺序搜索模块。
  • 可以通过修改sys.path添加自定义模块路径。

5.** 创建和使用自定义模块 **:

  • 创建.py文件定义函数、类和变量即可创建模块。
  • 使用if __name__ == "__main__":添加模块的测试代码。
  • 以下划线_开头的成员为私有成员,不建议外部访问。

课后任务

  1. 复习本节课的内容,确保理解模块的概念和导入方法。
  2. 完成课堂练习中的三个实战练习。
  3. 尝试使用其他内置模块(如ossys)完成一些简单的任务。
  4. 预习下一节课的内容:Python包与第三方库。

下一步学习建议

  1. 熟悉Python标准库中的常用模块,了解它们的功能和用法。
  2. 尝试将自己的代码组织成模块,提高代码的复用性和可维护性。
  3. 学习如何创建和使用Python包,组织多个相关模块。
  4. 了解如何安装和使用第三方库,扩展Python的功能。

模块是Python代码组织的基本单位,掌握模块的使用是编写大型Python程序的基础。通过不断练习和实践,你将能够更好地利用模块来组织和管理代码,提高编程效率和代码质量。
在这里插入图片描述

http://www.dtcms.com/a/389597.html

相关文章:

  • 异常检测patchcore 学习笔记 2025
  • [iOS] 网络 - AFNetWorking
  • iOS App 混淆与性能稳定性优化 混淆开销、崩溃风险、CI 集成与落地实务(
  • Freertos系统(任务挂起和恢复)
  • Git更新仓库时,忽略指定文件
  • 告别“瞎练”!数据闭环正成机器人智能进化核心引擎!
  • 基于MATLAB的无人机遥感数据预处理与农林植被性状估算
  • MATLAB基于AHP-模糊综合评价法的工程实践能力评价
  • 特征选择+优化算法+GBDT+SHAP分析!ReliefF-CPO-GBDT分类预测结合SHAP可解释分析MATLAB
  • 设计模式-外观模式详解
  • 《FastAPI零基础入门与进阶实战》第19篇:消息管理
  • 类和对象(下):static成员、友元类、内部类、匿名对象、优化——对象拷贝时的编译器优化
  • 虚拟线程(Virtual Thread)
  • 1688 店铺全商品接口技术全解:从页面解析到分页采集的完整实现方案
  • 日志轮转策略针对香港VPS存储空间的设置标准
  • 线性分组码及其相关概念
  • JWT的工作流程
  • Java 25 新特性 更简洁、更高效、更现代
  • 探讨前端与后端的安全策略:保护用户数据的关键措施
  • 如何使用DeepSeek等AI工具来帮助自己的工作
  • 灵途科技亮相CIOE2025 | 光电感知赋能具身智能升级
  • 我的云端影院:LibreTV+cpolar的异地观影记
  • NW748NW765美光固态闪存NW775NW781
  • 软考中级习题与解答——第八章_计算机网络(1)
  • Playwright 完全指南:从入门到实战,解锁自动化测试新范式
  • OpenCV:直接用NV21/NV12格式,画线、贴图都是相加效果,而不是替换、覆盖
  • MCP3421与STM32电压采集实现
  • 表白网页制作免费网站制作 表白网站建设教程
  • 嵌入式Linux C语言程序设计一、二
  • cocos做简单自动发射追踪子弹 切换敌人