什么是模块?#
在本章以前,我们一直将编写的代码放在一个 .py 源文件文件中,但已经尝试过使用 Python 的内建模块,如 math 和 random。随着代码规模的增大,将不可避免地需要将代码放在多个 .py 源文件中,这能方便对代码的组织管理,这时就要使用模块的概念。
模块(Module)就是以 .py 结尾的 Python 源文件,它包含定义(变量、函数和类)和语句。模块是 Python 代码的组织单元,它实际上也是一种对象。模块对应一个名字空间,其中包含任意的对象。
创建模块#
要创建模块,只需将模块代码保存在文件扩展名为 .py 的文件中。以下是 say_hello.py 文件内容:
hello_words = {'en-US': 'Hello!', 'zh-CN': '您好!',
'zh-TW': '您好!', 'ja-JP': 'こんにちは',
'nl-NL': 'Hallo', 'ko-KR': '안녕하세요'}
def hello(lang='zh-CN'):
print(hello_words[lang])
该文件对应的模块名称为 say_hello。模块命名和变量的命名习惯类似,即采用蛇形命名法。
导入并使用模块#
要在其他文件中使用刚创建的模块,必须先使用 import 语句导入此模块,有多种不同的导入方法。
最常规的导入方式是 import module_name,该语句会执行模块中的语句,进一步可以 module_name.name 的方式引用模块中的名称。如下为与 say_hello.py 同在一个目录下的 main.py 文件的内容:
import say_hello
say_hello.hello_words['it-IT'] = 'Ciao'
say_hello.hello('nl-NL') # Hallo
say_hello.hello('it-IT') # Ciao
在导入模块时,还可以在模块名后使用 import module_name as alias 为模块指定别名:
import say_hello as say
say.hello_words['it-IT'] = 'Ciao'
say.hello('nl-NL') # Hallo
say.hello('it-IT') # Ciao
可以使用 from module_name import name1, name2 的形式只导入模块中的特定名称到当前命名空间(namespace)。如果要同时导入多个名称,各项之间以逗号分割。如下所示:
from say_hello import hello_words, hello
hello_words['it-IT'] = 'Ciao'
hello('nl-NL') # Hallo
hello('it-IT') # Ciao
这时使用这些名称时不需要也不能使用前导的 module_name.,即应该用 hello('nl-NL') 而不是 。say_hello.hello('nl-NL')
也可以使用 from module_name import * 的形式直接将模块中所有的公开名称(不以下划线 _ 开头的名称)导入到当前命名空间:
from say_hello import *
hello_words['it-IT'] = 'Ciao'
hello('nl-NL') # Hallo
hello('it-IT') # Ciao
但这种方式常常会导入大量的未预料的名称,这些名称甚至会遮蔽已有的名称,因此通常不建议使用。
还可以使用 from module_name import name as alias 的形式为特定导入名称指定别名:
from say_hello import hello as hi
hi('nl-NL') # Hallo
模块搜索路径#
当导入一个模块 module_name 时,会按如下顺序寻找该模块:
-
检查该名称是否为内置模块;
-
如果不是内置模块,会在
sys.path目录列表中查找此模块,其查找顺序为:- 输入脚本的目录(或未指定文件时的当前目录);
PYTHONPATH环境变量所列出的目录- 依赖于安装的默认值(按照惯例包括一个
site-packages目录,由site模块处理)。
更多信息,请沿着以上链接进一步学习。
查看模块信息#
① 使用 dir() 函数#
内置的 dir() 函数会返回经过排序的对象属性名称列表,可借此函数查看模块的属性:
import say_hello
print(dir()) # 没有实参时,返回当前本地作用域中的名称列表
# ['__annotations__', '__builtins__', '__cached__',
# '__doc__', '__file__', '__loader__', '__name__',
# '__package__', '__spec__', 'say_hello']
print(dir(say_hello)) # 有实参时,尝试返回该对象的有效属性列表
# ['__builtins__', '__cached__', '__doc__',
# '__file__', '__loader__', '__name__',
# '__package__', '__spec__', 'hello', 'hello_words']
② 模块属性使用示例#
可以进一步使用这些内置的名称,如下所示:
print(__name__) # __main__
print(__package__) # None
print(say_hello.__cached__)
# C:\Users\jin\PycharmProjects\module\__pycache__\say_hello.cpython-310.pyc
print(say_hello.__doc__) # None
print(say_hello.__file__)
# C:\Users\jin\PycharmProjects\module\say_hello.py
print(say_hello.__name__) # say_hello
使用 PyCharm 建立 Python 项目时,其默认生成的 main.py 文件具有以下代码:
if __name__ == '__main__':
...
'__main__' 始终是当前执行模块内置变量 __name__ 的值。此 if 语句的条件确保 main.py 文件对应的 main 模块在被导入到其他模块后,其语句体不会被执行(因为被导入后该模块的 __name__ 变量值是 'main' 而不是 '__main__')。这正是我们想要的,因为我们本不想让 main 模块被其他模块导入和执行,这使得该 if 语句的句体看起来像其他语言的 main() 入口函数。
③ 查看已被加载的模块#
sys 是 Python 中一个比较重要的内建模块,它提供一些和系统相关的变量和函数。其中 sys.modules 变量会存储已经加载的模块:
import say_hello, sys
print(sys.modules)
# {'sys': <module 'sys' (built-in)>,
# 'builtins': <module 'builtins' (built-in)>,
# ...
# 'say_hello': <module 'say_hello' from 'C:\\Users\\jin\\PycharmProjects\\module\\say_hello.py'>}
可以看出 sys.modules 是字典类型,它将模块名称映射到已经被加载的模块。可借此查看某一模块的信息:
print(sys.modules['say_hello'])
# <module 'say_hello' from 'C:\\Users\\jin\\PycharmProjects\\module\\say_hello.py'>