常用模块-模块介绍,包以及包的导入

本文概要

本文主要讲解以下几个知识点:

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支持相对导入,但对模块间的路径关系要求比较严格,处理不当就容易出错,所以不建议在项目里使用。

 

 

版权声明:
作者:admin
链接:https://www.chenxie.net/archives/1781.html
来源:蜀小陈
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录