目录
(一)何为模块
(二)编写第一个模块
(三)import语句
(四)模块搜索路径
自建模块的存放位置
模块内部私有名称
(五)python的作用域的相关规则
主要内容
python语言如果没有众多的库作为支撑的话,那python作为一门编程语言存在意义也不大了。正是多种多样的标准库和诸多第三方库的存在,才让python具有了强大的功能。
模块、包和库的作用基本都是相同的,都是为了实现代码的重复利用,提高代码效率。区别是从模块到包再到库,代码数量越多,实现的功能越强大。当然,也会有一些管理工具。这里先简单了解一下模块。
模块(module)用于组织较大的Python项目,Python标准库被拆分为多个模块,以便更易于管理。
模块是一个包含代码的文件,其中定义了一组Python函数或其他对象,而且模块的名称来自文件名。
模块通常包含Python源代码,但也可以是经过编译的C或C++对象文件。经过编译的模块和Python源代码模块的用法是一样的。
模块不仅可以将相互关联的Python对象归并成组,还有助于避免命名冲突(name-clash)问题。因为Python采用了命名空间(namespace)的机制,所以使用模块名可以同时保留两个reverse函数。命名空间本质上就是标识符的字典,可用于代码块、函数、类、模块等。
我们将通过编写一个简单的模块来了解模块。
首先新建一个mymath.py文件,注意将文件保存在可执行文件所在的目录中。我的文件目录是D:\python37,通过下面的IDLE编辑器窗口也可以看到。
选择File>New Windows菜单,输入以下代码:
以上我们便简单定义了一个模块,这个模块只是定义了pi常数和新建一个函数。
下面我们需要在我们的代码中使用这个模块,需要注意的是,使用前一定要导入模块,如果未进行import语句导入,Python解释器会进行报错:
>>> pi
Traceback (most recent call last):
File "", line 1, in
pi
NameError: name 'pi' is not defined
>>> area(3)
Traceback (most recent call last):
File "", line 1, in
area(3)
NameError: name 'area' is not defined
也就是说,Python没有内置常量pi和函数area。我们将模块导入之后:
>>> import mymath
>>> pi
Traceback (most recent call last):
File "", line 1, in
pi
NameError: name 'pi' is not defined
>>> area(3)
Traceback (most recent call last):
File "", line 1, in
area(3)
NameError: name 'area' is not defined
结果Python解释器也报错了,这是因为Python解释器不知到变量pi和area函数在哪个模块里面,有可能其他的模块也有相同命名的函数和常量,为了解决这个问题,我们需要在常量和函数之前,加上模块名称。这种访问方式常常被称为限定名称(qualification),即变量pi是受mymath模块限定的。也可以将pi成为mymath的属性。代码如下:
>>> mymath.pi
3.14
>>> mymath.area(3)
28.259999999999998
模块中的对象可以直接访问同一模块内定义的其他对象,不需要带上模块名称。函数mymath.area访问常量mymath.pi时,只需要用pi即可。
还可以要求从模块中导入指定的对象名称,这样在使用时就不需要带上模块名称了。例如:
>>> from mymath import pi
>>> pi
3.14
模块不仅是在交互式Python shell中需要用到。模块还可以被导入脚本文件,或者其他模块中,只要在代码文件的开头输入合适的import语句即可。从本事上来说,对于Python,交互式会话和脚本也被认为是模块。总结如下:
可以通过dir()函数查看模块的方法:
>>> import os
>>> dir(os)
['DirEntry', 'F_OK', 'MutableMapping', 'O_APPEND', 'O_BINARY', 'O_CREAT', 'O_EXCL', 'O_NOINHERIT', 'O_RANDOM', 'O_RDONLY', 'O_RDWR', 'O_SEQUENTIAL', 'O_SHORT_LIVED', 'O_TEMPORARY', 'O_TEXT', 'O_TRUNC', 'O_WRONLY', 'P_DETACH', 'P_NOWAIT', 'P_NOWAITO', 'P_OVERLAY', 'P_WAIT', 'PathLike', 'R_OK', 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'TMP_MAX', 'W_OK', 'X_OK', '_Environ', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_execvpe', '_exists', '_exit', '_fspath', '_get_exports_list', '_putenv', '_unsetenv', '_wrap_close', 'abc', 'abort', 'access', 'altsep', 'chdir', 'chmod', 'close', 'closerange', 'cpu_count', 'curdir', 'defpath', 'device_encoding', 'devnull', 'dup', 'dup2', 'environ', 'error', 'execl', 'execle', 'execlp', 'execlpe', 'execv', 'execve', 'execvp', 'execvpe', 'extsep', 'fdopen', 'fsdecode', 'fsencode', 'fspath', 'fstat', 'fsync', 'ftruncate', 'get_exec_path', 'get_handle_inheritable', 'get_inheritable', 'get_terminal_size', 'getcwd', 'getcwdb', 'getenv', 'getlogin', 'getpid', 'getppid', 'isatty', 'kill', 'linesep', 'link', 'listdir', 'lseek', 'lstat', 'makedirs', 'mkdir', 'name', 'open', 'pardir', 'path', 'pathsep', 'pipe', 'popen', 'putenv', 'read', 'readlink', 'remove', 'removedirs', 'rename', 'renames', 'replace', 'rmdir', 'scandir', 'sep', 'set_handle_inheritable', 'set_inheritable', 'spawnl', 'spawnle', 'spawnv', 'spawnve', 'st', 'startfile', 'stat', 'stat_result', 'statvfs_result', 'strerror', 'supports_bytes_environ', 'supports_dir_fd', 'supports_effective_ids', 'supports_fd', 'supports_follow_symlinks', 'symlink', 'sys', 'system', 'terminal_size', 'times', 'times_result', 'truncate', 'umask', 'uname_result', 'unlink', 'urandom', 'utime', 'waitpid', 'walk', 'write']
import语句有3种格式,最基本的格式就是:
# 第一种,最基本的格式
import modulename
这时会搜索给定名称的Python模块,解析模块内容并使之进入可用状态。发起导入的代码可以使用模块中的内容,但是引用模块中的对象名称时仍必须带有模块名前缀。如果未找到指定名称的模块,就会报错。
第二种:
# 第二种,允许指定模块中的名称,将其显式的导入代码中
from modulename import name1, name2, name3, ...
这些name1、name2等modulename中的对象名称,就可供发起导入的代码使用了。在import语句之后的代码,可以直接使用name1、name2等名称,不需要再带上模块名前缀了。
# 第三种
from modulename import *
“ * ”代表模块modulename中所有导出(exported)的对象名称。
Python搜索模块的确切路径是在一个名为path的变量中定义的,可以通过模块sys访问path变量。
>>> import sys
>>> sys.path
['', 'D:\\python37\\Lib\\idlelib', 'D:\\python37\\python37.zip', 'D:\\python37\\DLLs', 'D:\\python37\\lib', 'D:\\python37', 'C:\\Users\\name\\AppData\\Roaming\\Python\\Python37\\site-packages', 'D:\\python37\\lib\\site-packages']
显示的位置取决于当前的系统配置。不管具体内容是什么,该字符串给出的是一个目录列表。当准备执行import语句时,Python将按顺序遍历该目录列表,并采用第一个满足import需求的模块。如果搜索路径中找不到合适的模块,则会引发ImportError异常。
为确保程序可以使用自己编写的模块,有以下三种方式:
模块中下划线开头的标识符不能用from module import *导入,所以将所有内部对象名称(即不允许模块外部访问的名称)都以下划线开头,既可以保证from module import *只引入用户需要访问的名称。
但是,也可以通过from module import _g语句,只导入_g变量,后面的代码就可以访问_g变量。
这里的核心概念是命名空间(namespace)。Python中的命名空间是从标识符到对象的映射,也就是Python如何跟踪变量和标识符是否活动以及指向什么。
如果刚刚接触Python,可以先不去了解这些。
Python 的名字查找规则是按照 local -> enclosing functions -> global -> built-in 的顺序由内而外查找,并选择最近的一个。
关于作用域规则,这里要先有一个概念,后续的学习中我们再逐步理解它。
参考: