模块是组织代码、实现复用、提升开发效率的关键元素。它们如同积木块一样,构成了Python程序的基石。本
一、理解Python模块:定义与基本特性
1. 定义
模块,简单来说,就是包含Python定义和语句的文件。它可以是一个.py文件,也可以是一个目录(含有__init__.py文件),甚至是一个自定义的C扩展。模块为代码提供了封装、复用和命名空间管理的功能,使得大型项目能够以更清晰、模块化的形式进行组织。
2. 基本特性
- 代码复用:模块允许开发者将常用功能、类或函数封装在一个单独的文件中,便于在多个地方重复使用,避免代码冗余。
- 命名空间管理:每个模块都有自己的命名空间,通过模块导入机制,可以有效避免变量名冲突,提高代码可读性和维护性。
- 模块化设计:模块化使程序结构清晰,易于理解和分工协作,遵循"高内聚、低耦合"的原则,有利于复杂项目的开发和管理。
- 系统资源隔离:模块有助于将不同功能的代码隔离开来,减少全局变量的使用,降低系统间的相互影响。
二、Python模块的结构与创建
1. 模块结构
一个典型的Python模块文件通常包含以下部分:
- 文档字符串(docstring) :位于模块文件开头,用于描述模块的功能、接口、使用方法等,可通过内置函数
help()
或pydoc
工具访问。 - 变量定义:包括常量、数据结构等,供模块内部或外部使用。
- 函数定义:实现特定功能的独立代码块,对外提供服务。
- 类定义:定义对象的属性和行为,实现面向对象编程。
- 模块级代码:在模块文件顶层执行的代码,如初始化工作、注册信号处理器等。
2. 创建模块
创建一个Python模块非常简单,只需按照上述结构编写.py文件即可。例如,创建一个名为utils.py
的模块,内容如下:
python
"""
Utils module: Provides common utility functions.
Functions:
greeting(name: str) -> str: Returns a personalized greeting message.
"""
def greeting(name: str) -> str:
return f"Hello, {name}!"
# ... 其他函数和类定义
三、Python模块的导入与使用
1. 导入模块
Python提供了多种导入模块的方式,包括:
- 常规导入 :
import module_name
,直接导入整个模块,通过module_name.
访问其中的成员。 - 别名导入 :
import module_name as alias
,为模块指定别名,方便调用。 - 从模块导入特定成员 :
from module_name import member
,直接导入模块内的某个成员,无需通过模块名引用。 - 星号(*)导入 :
from module_name import *
,导入模块的所有成员到当前命名空间。不推荐使用,易导致命名冲突和代码不易理解。
2. 使用模块
导入模块后,即可使用其提供的变量、函数、类等资源。例如,对于上文创建的utils
模块:
如想要导入模块 utils
.py,需要把命令放在脚本的顶端:
python
import utils
print(utils.greeting("Alice")) # 输出:Hello, Alice!
# 或者使用别名导入
import utils as ut
print(ut.greeting("Bob")) # 输出:Hello, Bob!
3. 定位模块
当你导入一个模块,Python 解析器对模块位置的搜索顺序是:
- 当前目录
- 如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。
- 如果都找不到,Python 会察看默认路径。UNIX下,默认路径一般为 /usr/local/lib/python/
模块搜索路径存储在 system 模块的 sys.path 变量中。变量里包含当前目录,PYTHONPATH 和由安装过程决定的默认目录。
4. 命名空间和作用域
变量是拥有匹配对象的名字(标识符)。命名空间是一个包含了变量名称们(键)和它们各自相应的对象们(值)的字典。
一个 Python 表达式可以访问局部命名空间和全局命名空间里的变量。如果一个局部变量和一个全局变量重名,则局部变量会覆盖全局变量。
每个函数都有自己的命名空间。类的方法的作用域规则和通常函数的一样。
Python 会智能地猜测一个变量是局部的还是全局的,它假设任何在函数内赋值的变量都是局部的。
因此,如果要给全局变量在一个函数里赋值,必须使用 global 语句。
global VarName 的表达式会告诉 Python, VarName 是一个全局变量,这样 Python 就不会在局部命名空间里寻找这个变量了。
例如,我们在全局命名空间里定义一个变量 money。我们再在函数内给变量 money 赋值,然后 Python 会假定 money 是一个局部变量。然而,我们并没有在访问前声明一个局部变量 money,结果就是会出现一个 UnboundLocalError 的错误。取消 global 语句的注释就能解决这个问题。
python
Money = 2000
def AddMoney():
# 想改正代码就取消以下注释:
#global Money
Money=Money+1
print(Money)
AddMoney()
print(Money)
'''
执行会报错如下:
Traceback (most recent call last):
File "f:\学习\python\测试\test2.py", line 9, in <module>
AddMoney()
^^^^^^^^^^
File "f:\学习\python\测试\test2.py", line 6, in AddMoney
Money=Money+1
^^^^^
UnboundLocalError: cannot access local variable 'Money' where it is not associated with a value
PS F:\学习\python\测试>
因为money在这里是局部变量没有定义
money到底是什么呢?当你读到这行代码时,完全不知道money是什么,money是整数呢?还是字符串呢?换用更专业的术语,也就是说,变量money没有被定义。
当去掉注释后可以当做全局变量不会报错,也可以在函数里写money=0,但是外面打印出来的结果还是2000,因为局部变量不能被外面的引用
'''
四、Python标准库与第三方模块
1. Python标准库
Python自带一系列丰富的标准库模块,涵盖了网络通信、文件操作、数据处理、算法实现、系统接口等诸多领域。如os
、sys
、datetime
、json
、requests
等,这些都是Python编程的强大工具箱,极大地提高了开发效率。
2. 第三方模块
除了标准库外,Python生态还拥有庞大的第三方模块库,如numpy
、pandas
用于数据分析,tensorflow
、pytorch
用于深度学习,flask
、django
用于Web开发等。这些模块可通过pip
包管理器轻松安装,极大地扩展了Python的应用范围。
3.name
一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用 name 属性来使该程序块仅在该模块自身运行时执行。
python
#下面代码是test2.py下的代码
if __name__ == '__main__':
print('程序自身在运行')
else:
print('我被其他模块导入了,执行了else代码块')
#在test2.py里执行会输出:程序自身在运行
#下面是test.py里的代码
import test2
#执行后会输出:我被其他模块导入了,执行了else代码块
说明:
- 每个模块都有一个 name 属性,当其值是 'main' 时,表明该模块自身在运行,否则是被引入。
- name 与 main 底下是双下划线,是"_ _"去掉中间的空格。
4.dir()函数
会把模块下的函数都列出来
python
import sys
print(dir(sys))
#输出如下
['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__',
'__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__', '_base_executable', '_clear_type_cache', '_current_exceptions', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding', '_framework', '_getframe', '_getquickenedcount', '_git', '_home', '_stdlib_dir', '_xoptions', 'addaudithook', 'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix', 'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth', 'getallocatedblocks', 'getdefaultencoding', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'orig_argv',
'path', 'path_hooks', 'path_importer_cache', 'platform', 'platlibdir', 'prefix', 'pycache_prefix', 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setprofile', 'setrecursionlimit', 'setswitchinterval',
'settrace', 'stderr', 'stdin', 'stdlib_module_names', 'stdout', 'thread_info', 'unraisablehook', 'version',
'version_info', 'warnoptions', 'winver']