模块和包
为什么要有模块和包
在Python中,模块(Module)和包(Package)是组织和管理代码的重要工具,有助于将代码划分为可维护和重用的单元。
模块(Module)
-
概念:模块是一个包含Python代码的文件(通常以
.py
扩展名结尾)。一个模块可以包含变量、函数、类等,它提供了一种将相关功能组织在一起的方式。 -
命名空间:模块本身具有自己的全局命名空间,不同模块命名空间彼此隔离,通过模块可以避免命名冲突,使得相同名称的函数或变量在不同的模块中不会相互影响。
-
模块的属性: 模块还包括一些特殊的属性,如
__name__
,它指示模块的名称。__doc__
属性:__doc__
是一个用于存储模块文档字符串的特殊属性。文档字符串是对模块内容的描述,可以通过help()
函数查看。# mymodule.py # 当模块被直接运行时,__name__ 的值为 "__main__",用于判断是否是主模块。 if __name__ == "__main__":print("This module is being run directly.") else:print("This module is being imported.")
# mymodule.py"""This is the module docstring."""module_variable = "I am a module variable"def module_function():"""This is the function docstring."""print("I am a module function") # main.pyimport mymoduleprint(mymodule.__doc__) # 输出: This is the module docstring. print(mymodule.module_function.__doc__) # 输出: This is the function docstring.
-
模块的使用
# fibo.py # Fibonacci numbers moduledef fib(n): # write Fibonacci series up to na, b = 0, 1while a < n:print(a, end=' ')a, b = b, a+bprint()def fib2(n): # return Fibonacci series up to nresult = []a, b = 0, 1while a < n:result.append(a)a, b = b, a+breturn result
-
导入模块
import fibo # 直接导入 from fibo import fib, fib2 # 可以将来自某个模块的名称直接导入到导入方模块的命名空间 from fibo import * # 可以导入模块内定义的所有名称 import fibo as fib # 模块名后使用 as 时,直接把 as 后的名称与导入模块绑定 from fibo import fib as fibonacci # 将模块中的属性与as后名称绑定
-
以脚本方式执行模块
python fibo.py <arguments>
这个操作需要将以下代码加到模块底:
if __name__ == "__main__":import sysfib(int(sys.argv[1]))
-
-
模块搜索路径
-
内置模块: Python解释器会首先搜索内置模块,这些模块包含了一些核心的Python库和功能。
-
sys.path: Python解释器会查找 sys.path 变量,该变量是一个包含目录和.zip文件的列表。sys.path 的默认值包括以下几个部分:
包含脚本的目录(当前工作目录)PYTHONPATH 环境变量中列出的目录标准库的安装目录内置模块的安装目录用户自定义目录
-
-
“已编译的” Python 文件
在Python中,已编译的文件通常指的是以.pyc
扩展名结尾的文件。这些文件包含了原始的Python源代码的字节码形式,经过编译和优化以供Python解释器更高效地执行。生成和更新: 当你第一次导入一个模块时,解释器会检查是否存在对应的.pyc
文件。如果存在,它会比较源代码和已编译的字节码文件的时间戳。如果源代码没有变化,而且.pyc
文件仍然有效,解释器会直接加载已编译的字节码,而不重新生成。如果源代码发生变化或者没有.pyc
文件,解释器会重新生成并更新.pyc
文件。
包(Package)
-
概念: 包是一个包含模块和子包的目录,它允许你组织和管理大型项目中的模块。包是一个包含特殊文件
__init__.py
的目录。 -
创建包:为了将一个目录变成一个包,只需在该目录中创建一个
__init__.py
文件,它可以是空文件,也可以包含初始化包的代码。mypackage/ ├── __init__.py ├── module1.py ├── module2.py └── submodule/├── __init__.py└── module3.py
-
导入包中的模块: 使用
import
关键字可以导入包中的模块。可以通过点运算符(.
)访问子模块。import mypackage.module1 mypackage.module1.some_function()# 或者使用 as 给模块取别名 import mypackage.module1 as mod1 mod1.some_function()
-
__init__.py
的作用:__init__.py
文件是包的初始化文件,它可以包含一些包级别的代码,也可以为空。当导入一个包时,__init__.py
会首先被执行。- 包标识:将包目录标识为一个Python包
- 包初始化:
__init__.py
文件在导入包时会被执行。这意味着你可以在__init__.py
中执行一些初始化工作,例如设置包级别的变量、引入包内部的模块等。
# __init__.pypackage_variable = "I am a package variable" #设置包级别的变量
print("Initializing mypackage") # 执行初始化代码
__version__ = '1.0.0' # 表示版本号
__all__ = ['module1', 'module2'] # 在import *时只会导入这两个模块
-
相对导入: 相对导入允许在包内部的模块之间使用相对路径进行导入。
# 例如,在 submodule/module3.py 中可以这样导入 module1 from ..module1 import some_function