# 1.2.2 模块 在`Python`程序的开发过程中,为了代码维护的方便,我们可以把函数进行分组,分别放到不同的`.py`文件里,这样,每个文件包含的代码就相对较少,这个`.py`文件就称之为一个模块(`Module`)。模块能够让我们有逻辑地组织`Python`代码段,模块中能够定义函数,类和变量,模块里也可以包含可执行的代码。 ## 模块的引入 `Python`中要用关键字`import`来引入某个模块,比如要引用模块`math`,就要在文件的开头用`import math`来引入。在调用`math`模块中的函数时,引用格式为: `模块名.函数名` 因为这种调用方式可以避免特殊情况的发生:比如在多个模块中可能含有相同名称的函数,这时如果只是通过函数名来调用,程序无法知道是要调用哪个函数。所以如果用上述方法引入模块的时候,调用函数必须加上模块名。 例如: ```python import math print(fabs(-2)) ``` 输出结果: `NameError: name 'fabs' is not defined` `fabs()`必须加上`math`前缀,例如: ```python import math print(math.fabs(-2)) ``` 输出结果: `2` 有些时候我们只需要用到模块中的某个函数,这时不需要导入整个模块,只需要导入该函数即可,语句格式如下: `from 模块名 import 函数名1,函数名2....` 通过这种方式导入函数的时候,调用函数时就只能给出函数名,而不能给出模块名了。这种方式导入函数的方法会有这种缺陷:当两个模块中含有相同名称函数的时候,后面一次导入的函数会覆盖前一次导入的函数。例如,假如模块A中有函数`function()`,模块B中也有函数`function()`,如果先导入模块A中的`function()`、后导入模块B中的`function()`,那么当我们在后面调用`function()`函数的时候,程序是去执行模块B中的`function()`函数。 如果想一次性引入模块`math`中所有的函数,可以通过如下方式导入: `from math import *` ## 自定义模块 每个`Python`文件都可以看作一个模块,模块的名字就是`Python`文件的名字。所以我们完全可以自己写一个`Python`文件,就作为自己定义的模块。例如我们编写了`my_module.py`文件,里面定义了`plus()`函数: ```python #my_module.py def plus(a,b): return a+b ``` 之后我们就可以在其他`Python`文件中先`import my_module`,然后通过`my_module.plus(a,b)`来调用`my_module.py`文件中的`plus()`函数。我们也可以直接通过`from my_module import plus`来导入`plus()`函数。 ## 内置模块中的内置函数 我们在安装好了`Python`后,也将`Python`本身带有的库也安装好了,`Python`自带的库也叫做`Python`的内置模块。`Python`的内置模块是`Python`编程的重要组织形式,内置模块中的内置函数也极大方便了编程过程中对函数等功能的使用。 `Python`中常见的内置模块如下: 1. `os`模块:(文件和目录)用于提供系统级别的操作。 2. `sys`模块:用于提供对解释器相关的操作。 3. `json`模块:处理`JSON`字符串。 4. `logging`: 用于便捷记录日志且线程安全的模块。 5. `time&datetime`模块:时间相关的操作,时间有三种表示方式。 6. `hashlib`模块:用于加密相关操作,代替了`md5`模块,主要是提供`SHA1`,`SHA224`,`SHA256`,`SHA384`,`SHA512`,`MD5`算法。 7. `random`模块:提供随机数。 `Python`的内置模块中也有很多使用十分方便的内置函数。 `dir()`函数是一个排好序的字符串列表,包含的内容是一个模块里定义过的名字,包含在一个模块里定义的所有模块,变量和函数。例如: ```python # 导入内置math模块 import math #调用math模块中的dir()函数 content = dir(math) #输出math模块中所有模块、函数和变量的名字 print(content) ``` 输出结果: `['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs','factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin','sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']` 程序输出了`math`模块中所有模块、函数和变量的名字。特殊字符串变量`__name__`是指向模块的名字,变量`__file__`是指向该模块的导入文件名。 `globals()`和`locals()`函数可被用来返回全局和局部命名空间里的名字。如果在函数内部调用的是`globals()`函数,那么返回的是所有在该函数里能够访问的全局名字。如果在函数内部调用的`locals()`函数,返回的是能够在该函数里访问的局部命名。`globals()`函数和`locals()`函数的返回类型都是字典。所以名字们能用`keys()`函数摘取。 当一个模块被导入到一个脚本中后,程序只会将模块顶层部分的代码执行一次。因此,如果我们想再次执行模块顶层部分的代码,可以用`reload()`函数。该函数便会重新将之前导入过的模块导入。格式如下: `reload(module_name)` 在这里,`module_name`要直接放模块名,而不能是一个字符串形式。例如我们想重载`hello`模块: `reload(hello)`