常用模块
本文概要
本文主要讲解以下几个知识点:
1. 认识什么是模块
2. 模块有什么好处
3. 模块的分类
4. 模块的导入方法
5. 第三方开源模块的安装方法
6. 包的知识
什么是模块
在平时的开发过程中,随着代码越写越多,到最后如果要对某一处进行修改就显得难以维护了,稍不注意要是改错了就会出大问题。
所以为了维护的便捷,我们就把很多函数进行分组,放到不同的文件里,就可以通过文件名本身进行功能区分,每个文件里的代码量也会相对较少,更有利于维护,很多语言都是这样的,在Python里,一个.py文件就是一个模块。
使用模块有什么好处
1. 提高代码可维护性;
2. 可重用,编写代码不必从零开始,直接引用即可,其他地方也可以用;
3. 避免函数名和变量名冲突,因为一个文件中如果代码太多,就会声明有很多的函数名和变量名,有时候你在定义一个变量名时,自己都不知道是否已经用过了,分为多个文件,文件各自的作用域第独立的,所以能够尽量避免函数名和变量名的冲突。
模块的分类
1. 内置标准模块(又称标准库),是Python安装后自带的模块;
2. 第三方开源模块:从其他拷贝过来的,或第三方网站上安装的,通常从https://pypi.org/安装
3. 自定义模块:即自己写的,一个.py文件,里面写几个函数,也可以是模块。
导入模块的方法
# 导入整个sys模块,使用sys模块时,需要在功能前面加上sys,如:sys.getrecursionlimit() import sys # 从os模块中,只导入rmdir和rename两个功能,多个功能用逗号隔开。使用时功能前面不用加os,直接就可以使用,如:rmdir("abc.txt") from os import rmdir, rename # 从django的子模块core中导入handlers功能 from django.core import handlers # 模块太长了,导入multiprocessing模块并通过as取一个别名叫mul import multiprocessing as mul # 导入socket模块下所用的功能。 from socket import
注意:模块一旦被调用,就相当于执行了里面的代码。所以模块顶层一般不写执行代码,特殊除外。
模块的导入路径
导入自己的模块的是要要注意路径问题,相对路径和绝对路径。
Python默认的模块在哪里:
可以通过sys.path看到python使用哪些地方找的:
>>> import sys >>> sys.path ['', 'D:\\PycharmProjects\\python_fullstack_middle\\venv\\Scripts\\python36.zip', 'C:\\Python36\\DLLs', 'C:\\Python36\\lib', 'C:\\Python36', 'D:\\PycharmProjec ts\\python_fullstack_middle\\venv', 'D:\\PycharmProjects\\python_fullstack_middle\\venv\\lib\\site-packages', 'D:\\PycharmProjects\\python_fullstack_middle\\ve nv\\lib\\site-packages\\setuptools-39.0.1-py3.6.egg', 'D:\\PycharmProjects\\python_fullstack_middle\\venv\\lib\\site-packages\\pip-9.0.3-py3.6.egg'] >>>
第一个元素为空,表示是当前目录。
内置的模块和从第三方装的模块都会放到 site-packages 目录下。
添加自定义模块目录到sys.path里面:
sys.path.append("D:\\abc") # 表示我的模块存在D盘的abc目录下
导入和移除模块:
import my_module del my_module
开源模块的学习和安装方式
https://pypi.org/ 是Python的开源模块库,全世界的开发者都可以在上面贡献自己的模块。
两种安装方式:
这里以大王的一个例子项目为例:alex_sayhi ,搜索这个项目 点进去就会有安装方式。
方式一(源码安装):
如大王的项目,搜索到后,点击Download files 就可以找到下载链接,下载下来后解压,然后执行:
python setup.py build # 编译源码 python setup.py install # 安装源码
方式二(通过pip安装):
在项目页面上方就直接有安装命令:
pip install alex_sayhi
这种方式最简单,安装后在 site-packages 目录里面可以找到。
安装的时候的输出:
C:\>pip install alex_sayhi Collecting alex_sayhi Downloading https://files.pythonhosted.org/packages/84/14/b59d93276c86f6ab556cfa7c2d860b742c1611b601cc4c7743d129b4b52a/alex_sayhi-1.0.0.tar.gz Installing collected packages: alex-sayhi Running setup.py install for alex-sayhi ... done Successfully installed alex-sayhi-1.0.0 You are using pip version 9.0.1, however version 10.0.1 is available. You should consider upgrading via the 'python -m pip install --upgrade pip' command. C:\>
国内源:
从官网安装可以由于一些网络因素会很慢,我们可以选择使用国内的豆瓣源。
pip install -i http://pypi.douban.com/simple/ alex_sayhi --trusted-host pypi.douban.com #alex_sayhi是模块名
例子:
这里演示一个通过ssh执行命令的小程序:
需要导入两个模块:sys 和 paramiko sys只用到两个功能,所有通过 from sys import stdin, stdout 只导入两个功能
paramiko 不存在,需要新安装。
这地方有个坑的地方,我在cmd中通过 pip install paramiko 已经安装成功了,在cmd的python解释器里也能通通过 import paramiko导入模块,但是在PyCharm里面弄死导不进去,模块是已经确认安装到了C:\Python36\Lib\site-packages 的,在PyCharm里通过print(sys.path)查看发现没有 C:\Python36\Lib\site-packages 这个目录,这就是为什么导入不进去的原因,但是怎么加进去呢?没有找到方法。我通过另一种方式成功导入了,首先在PyCharm里先将 import paramiko敲上,paramiko会变红,双击paramiko然后按下Alt+Enter键就会提示你安装了,安装完了发现他是安装到我项目下的 \\venv\\lib\\site-packages 目录的,anyway 反正是可以正常工作了。
收点费
from sys import stdin, stdout import paramiko ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect("192.168.1.100", 22, "root", "123456") stdin, stdout, stderr = ssh.exec_command("df -h") print(stdout.read()) ssh.close()
输出:
b'Filesystem Size Used Avail Use% Mounted on\n/dev/xvda1 20G 9.9G 8.8G 53% /\ntmpfs 7.8G 8.0K 7.8G 1% /dev/shm\n/dev/mapper/VolGroup-data\n 788G 604G 145G 81% /data\n'
包
当模块越来越多时,一个大的功能可能包含多个模块,这时候我们可以将他们分类放到一个统一的目录当中,又或者把与数据库交互的放到一个目录,与页面展现的放到一个目录,一个目录管理多个模块,这个目录就是包。
如何确定这个目录是包:
python2 中目录下必须要有一个空文件 __init__.py 目录就会自动识别为包,没有的话就是一个普通目录。
python3 可以不需要这个空文件,但是还是建议加上。
用了包之后模块怎么导入:
三种情况
如下,现在的目录结构如下:
第一种:运行文件在包之外。
现在manage.py 调 crm包下的 view.py模块。
在 crm/view.py 里的代码如下:
def show_pic(): print("show pic") def show_file(): print("show_file")
manage.py 和 crm、database两个包是同级的,在manage.py里调 view.py 模块:
manag.py的代码如下:
from crm import view; view.show_pic()
运行 manage.py 的结果为:
show pic
这里在PyCharm里 有红色的报错,但是没有影响:
第二种:模块在同一个包内
现在 ui.py 模块要调 view.py 模块。
ui.py 代码如下:
import view view.show_pic()
运行 ui.py 结果为:
show pic
没有问题,导入成功。 PyCharm 依然会有红色报错,不影响,不管他
第三种:导入的模块在另一个包下面
现在 ui.py 要导入在database包下面的 db.py
这时候再像之前搞那样导入就会出现问题了,需要添加环境变量来实现,就是将crm上一层的路径 也就是 包 添加到 sys.path 中
ui.py 代码如下:
import sys sys.path.append("D:\PycharmProjects\python_fullstack_middle\第二模块:函数编程\第2章.常用模块\包") # 添加环境变量 from database import db # 导入database下的db模块 db.mysql() # 调用db模块里的函数
运行 ui.py 结果如下:
mysql
没有问题,成功。
但是上面添加环境变量时写的是绝对路径,假如我将程序拷贝到其他人机器上,那必然会报错,所以 我们来调整一下。
调整后 ui.py 的代码如下:
import sys, os BASE_PATH1 = os.path.dirname(__file__) # 通过 os.path.dirname(__file__) 获取到 ui.py 的所在目录路径 BASE_PATH2 = os.path.dirname(os.path.dirname(__file__)) # 再包一层 os.path.dirname() 又继续向上获取一层 print(BASE_PATH1) # 输出:D:/PycharmProjects/python_fullstack_middle/第二模块:函数编程/第2章.常用模块/包/crm print(BASE_PATH2) # 输出:D:/PycharmProjects/python_fullstack_middle/第二模块:函数编程/第2章.常用模块/包 sys.path.append(BASE_PATH2) from database import db # 导入database下的db模块 db.mysql() # 调用db模块里的函数
运行 ui.py 结果为:
D:/PycharmProjects/python_fullstack_middle/第二模块:函数编程/第2章.常用模块/包/crm D:/PycharmProjects/python_fullstack_middle/第二模块:函数编程/第2章.常用模块/包 mysql
成功,没有问题,并且实现了动态的路径获取。
再来一个问题,我之前是在 crm/ui.py 模块中调 database/db.py 模块,运行的 ui.py 模块,
现在 我还是 在 crm/ui.py 模块中调 database/db.py 模块,不过 我现在在 db.py 模块中 再调 database包下的 happy.py 模块 ,还是运行的 ui.py ,这时候你就想呀 happy.py 模块 和 db.py 都在同一个目录下 那就再db.py模块中直接写 import happy ,这时候你会发现报错了 "No module named 'happy'",咋回事,这是因为你运行的是 ui.py ,ui.py 里你直接写 import happy 它会从ui.py 同级的包里去找,肯定是找不到的,由于你已经ui.py上上级的的路径添加到环境变量sys.path了,所以要写成 from database import happy 就不会出错了。
绝对导入与相对导入
上面讲的就是绝对导入。
接下来讲解 相对导入。
在 linux 中,我们可以通过 cd .. 回到上一层 , cd ../../ 回到上上层,在python中也是可以的。
如下图,我在crm/view.py 模块中 通过相对导入 导入database/db.py ,然后运行view.py 结果报错了 ValueError: attempted relative import beyond top-level package
为什么会这样呢?
因为 在涉及到相对导入时,package所对应的文件夹必须正确的被python解释器视作package,而不是普通文件夹。否则由于不被视作 package,无法利用package之间的嵌套关系实现python中包的相对导入。
文件夹被python解释器视作package需要满足两个条件:
1. 文件夹中必须有 __init__.py 文件,该文件可以为空,但必须存在该文件。
2. 不能作为顶层模块来执行该文件夹中的py文件(即不能作为主函数的入口)
也就是说,你如果view.py使用相对对导入的方式,就不要把view.py 作为入口程序,就不能直接运行 view.py.
解决办法就是可以通过上一级的 manage.py 来调用 view.py
好,现在我运行 manage.py ,擦, 还是报一样的错,搞毛线啊:
但是 我如果在 view.py 里 把 from ..database import db 改为 from . import ui 就改为导入和view.py 同级的 ui.py ,再执行 manage.py 就不会报错。
ok, 那怎么才能够 使用 from ..database import db 并且不报错呢?
将 manage.py 往上移动一级,因为 from ..database import db 会把 manage.py 所在的这一层视作package,但实际上它不是,因为package不能是顶层入口diamante,若不像出错,只能把manage.py往上移一层。
这里我新建一个 pack包,然后将crm 和 database都移动进去,修改manage.py 改为 from pack.crm import view 再次执行 就不会报错了。
注意:虽然python支持相对导入,但对模块间的路径关系要求比较严格,处理不当就容易出错,所以不建议在项目里使用。