4 道练习题·预计 45 分钟·做对一题解锁下一段
学习到这里,可以说 Python 基础学习基本接近尾声了。
这一篇会按下面的脉络展开:
在开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。
后面我们学习了函数,知道函数是实现一项或多项功能的一段程序,这样就更方便我们重复使用代码。
紧接着,我们有学了类,类可以封装方法和变量(属性)。这样就更方便我们维护代码了。
我们之前学过,类的结构是这样的:
而我们要学的模块是这样的:
在模块中,我们不但可以直接存放变量,还能存放函数,还能存放类。
不知道你们还有没有印象,我们封装函数用的是 def , 封装类用的是 class 。
而我们封装模块,是不需要任何语句的。
在 Python 中,一个 .py 文件就称之为一个模块(Module)。
可以看下我之前写的例子,在 pychrome 上 ,这样一个 test.py 文件就是一个模块。
test ~/dev/python/test
├── com
│ └── twowater
│ ├── __init__.py
│ ├── iter.py
│ └── test.py ← 这里就是一个模块
│ └── __init__.py
└── venv
# test.py 的内容:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-其实模块就是函数功能的扩展。为什么这么说呢?
那是因为模块其实就是实现一项或多项功能的程序块。
通过上面的定义,不难发现,函数和模块都是用来实现功能的,只是模块的范围比函数广,在模块中,可以有多个函数。
然有了函数,那为啥那需要模块?
最大的好处是大大提高了代码的可维护性。
其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括 Python 内置的模块和来自第三方的模块。
使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。
Python 本身就内置了很多非常有用的模块,只要安装完毕,这些模块就可以立刻使用。我们可以尝试找下这些模块,比如我的 Python 安装目录是默认的安装目录,在 C:\Users\Administrator\AppData\Local\Programs\Python\Python36 ,然后找到 Lib 目录,就可以发现里面全部都是模块,没错,这些 .py 文件就是模块了。
Lib 目录下的部分文件大致是这样的:
| 文件 | 修改时间 | 大小 |
|---|---|---|
_compat_pickle.py | 2017/2/13 22:38 | 9 KB |
_compression.py | 2017/2/13 22:38 | 6 KB |
_dummy_thread.py | 2017/2/13 22:38 | 6 KB |
_markupbase.py | 2017/2/13 22:38 | 15 KB |
_osx_support.py | 2017/2/13 22:38 | 20 KB |
_pydecimal.py | 2017/3/21 17:46 | 232 KB |
_pyio.py | 2017/3/21 17:46 | 89 KB |
_sitebuiltins.py | 2017/2/13 22:38 | 4 KB |
_strptime.py | 2017/2/13 22:38 | 25 KB |
_threading_local.py | 2017/2/13 22:38 | 8 KB |
_weakrefset.py | 2017/2/13 22:38 | 6 KB |
abc.py | 2017/2/13 22:38 | 9 KB |
aifc.py | 2017/3/4 5:11 | 33 KB |
antigravity.py | 2017/2/13 22:38 | 1 KB |
argparse.py | 2017/2/13 22:38 | 91 KB |
ast.py | 2017/3/21 17:46 | 13 KB |
其实模块可以分为标准库模块和自定义模块,而刚刚我们看到的 Lib 目录下的都是标准库模块。
Python 模块的使用跟其他编程语言也是类似的。你要使用某个模块,在使用之前,必须要导入这个模块。导入模块我们使用关键字 import。
import 的语法基本如下:
import module1[, module2[,... moduleN]比如我们使用标准库模块中的 math 模块。当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import math
_author_ = '两点水'
print(math.pi)输出的结果:
3.141592653589793一个模块只会被导入一次,不管你执行了多少次 import。这样可以防止导入模块被一遍又一遍地执行。
当我们使用 import 语句的时候,Python 解释器是怎样找到对应的文件的呢?
这就涉及到 Python 的搜索路径,搜索路径是由一系列目录名组成的,Python 解释器就依次从这些目录中去寻找所引入的模块。这看起来很像环境变量,事实上,也可以通过定义环境变量的方式来确定搜索路径。搜索路径是在 Python 编译或安装的时候确定的,安装新的库应该也会修改。搜索路径被存储在sys 模块中的 path 变量 。
因此,我们可以查一下路径:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import sys
print(sys.path)输出结果:
['C:\\Users\\Administrator\\Desktop\\Python\\Python8Code', 'G:\\PyCharm 2017.1.4\\helpers\\pycharm', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\python36.zip', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\DLLs', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\lib', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\lib\\site-packages', 'C:\\Users\\Administrator\\Desktop\\Python\\Python8Code\\com\\Learn\\module\\sys']
有没有想过,怎么直接导入某个模块中的属性和方法呢?
Python 中,导入一个模块的方法我们使用的是 import 关键字,这样做是导入了这个模块,这里需要注意了,这样做只是导入了模块,并没有导入模块中具体的某个属性或方法的。而我们想直接导入某个模块中的某一个功能,也就是属性和方法的话,我们可以使用 from···import 语句。
语法如下:
from modname import name1[, name2[, ... nameN]]看完简介后可能会想, from···import 和 import 方法有啥区别呢?
想知道区别是什么,观察下面两个例子:
import 导入 sys 模块,然后使用 version 属性
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import sys
print(sys.version) # 通过导入的 sys 模块,调用里面的方法或属性
print(version) # 会报错,没法直接使用 version 属性,因为导入的只是 sys 这个模块运行结果:
3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)]
NameError: name 'version' is not definedfrom···import 直接导入 version 属性
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
from sys import version
print(version) # 直接使用 version 属性,无需 sys. 前缀运行结果:
3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)]通过上面的学习,我们知道了 from sys import version 可以直接导入 version 属性。
但是如果我们想使用其他的属性呢?
比如使用 sys 模块中的 executable ,难道又要写多一句 from sys import executable ,两个还好,如果三个,四个呢?
难道要一直这样写下去?
这时候就需要 from ··· import * 语句了,这个语句可以把某个模块中的所有方法属性都导入。比如:
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
from sys import *
print(version)
print(executable)
输出的结果为:
3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)]
C:\Users\Administrator\AppData\Local\Programs\Python\Python36\python.exe注意:这提供了一个简单的方法来导入一个模块中的所有方法属性。然而这种声明不该被过多地使用。
模块不必一个一个背。先明确眼前的需求:把一个数向上取整。我们去标准库文档里找到 math.ceil,看它接收什么、返回什么,再用很小的输入验证。
from math import ceil
print(ceil(2.1))
print(ceil(0))
print(ceil(-2.1))输出:
3
0
-2负数这个结果很值得停下来想一下:向上取整不是把数字的绝对值变大。阅读函数说明以后,用正数、零和负数核对,比只试一个正数更容易发现理解偏差。
后面综合项目会把函数放进 tracker.py,测试文件再导入它。导入模块和直接执行脚本的目的不同;if __name__ == '__main__' 可以让命令行入口只在直接执行时启动,避免测试导入时就要求输入命令参数。
如果遇到导入失败,先记录实际运行的 Python、当前目录、文件名和完整错误。把无关业务代码去掉,只保留那句导入验证。自己的文件也不要随便取成 math.py、json.py,否则可能遮住本来想导入的模块。
请用 import 引入 math 模块,然后利用 math.pi:
r = 5 时的圆周长,公式 2 * math.pi * rround(..., 4))赋给变量 cprint(c)输出应该是:
31.4159推荐一个,全网最全最友好的中文 AI 编程指南: coding.stormzhang.ai