文章目录
模块介绍
简单来说模块就是一个包含自己或他人定义的函数和变量的文件,当我们需要使用的时候就可以拿过来使用,这些模块的功能十分强大,可以看作是各种功能的结合体,是为各个大佬所编写。
模块的来源
模块有三种来源:
1.内置的模块
无需下载 解释器自带 直接导入使用即可
2.自定义模块
自己写的代码 封装成模块 自己用或者发布到网上供别人使用
3.第三方模块
别人写的发布到网上的 可以下载使用的模块(很多牛逼的模块都是第三方)
第三方模块下载
首先查看当前解释器下载的第三方模块,通常都是借助于编辑器查看。
在 pycharm 里的 settings... 下的 Project 下的 python interprter 里查看有没有第三方模块。
下载方式一:
直接使用在cmd终端用输入命令行下载。
语法为: pip3 install 模块名 '''该方式默认下载的是最新版本'''
或者: pip3 install 模块名==版本号 '''自定义下载版本号'''
'pip工具默认是从国外的仓库下载模块 速度会比较慢 可以修改'
修改语法: pip3 install 模块名 -i 仓库地址 '''命令行临时修改地址'''
仓库地址可以使用国内的地址:
(1)阿里云http://mirrors.aliyun.com/pypi/simple/
(2)豆瓣http://pypi.douban.com/simple/
(3)清华大学https://pypi.tuna.tsinghua.edu.cn/simple/
(4)中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/
(5)华中科技大学http://pypi.hustunique.com/
下载方式二:
利用 pycharm 提供的快捷方法
到查看第三方模块的界面下有一个加号键,点击加号然后在弹出的界面搜索框里找到需要的模块
在选择模块的时候右下 Specify version 选项选择版本号。
同样也可以换源,在选择模块界面中的 Manage Repositories 点击,将网址填入即可。
下载方式三:
直接先导入一个想要的模块名,若是不存在会有提示,也就是像灯笼一样的提示,点击其中的下载。
下载模块的时候有时候会报错
1.报错信息中含有timeout关键字
原因是你当前计算机的网络不稳定 重新执行多次或者切换网络
2.报错信息中没有太多的关键字 并且很长
拷贝最后一行错误信息 去百度
模块的表现形式
1.使用python代码编写的py文件
2.多个py文件组成的文件夹(包)
3.已被编译为共享库或DLL的c或C++扩展
4.使用C编写并链接到python解释器的内置模块
模块的导入方式
模块有俩种导入方式
方式一 import ...
代码示例
import time
import time
time.time()
---import 模块名---
在之前的文章中已经有用到的 time 模块,这里使用 import 的方式导入模块,需要注意的是,导入模块的
语句只要一次就行,因为执行了一次,在导入同样的模块是不起作用的。
导入模块后,可以使用该模块里面的内容了。使用 import 的方法导入模块我们使用的时候要先写出模块的
名字,然后点一下就能看到并使用里面的方法了。
在使用模块里面的方法的时候,有可能变量或者函数的名字和当前python文件的变量、函数名相同,但是不
用管他,因为我们使用的是模块里面的变量,而不是当前的变量,所以不会冲突。
也可以同时导入多个包,不过还是分开比较好
代码示例
import time, sys
示意图
import … 导入的示意图
- 首先执行语句 import time ,此时相当于执行了模块 time ,也就是说开辟了一个名称空间里面存放着模块 time 的所有变量名称,而我们当前的文件在执行的时候也会有一个名称空间被开辟。
- 执行语句 time.sleep() 也就是调用了模块里的函数 sleep() ,它指向的是模块名称空间里面的函数名 sleep ,与当前文件无关,所以我们定义一个重名的函数 sleep() 也不会造成冲突。
- 但是,需要注意的是,我们在执行导入语句的时候,相当于在当前文件的名称空间中产生一个模块的名字指向模块的名称空间 ,也就是说,如果修改了模块的名字也就是 time 的值,模块的功能就都会失效不能使用。因为我们是通过模块的名字才能使用里面的方法。
方式二 from...import...
代码示例
from time import sleep
sleep(5)
---from 模块名 import 需要导入的指定部分---
和 import 导入不同,此时相当于在当前文件产生了一个模块的函数名指向模块的名称空间里面的函数名。所
以我们可以直接调用函数就行而不是使用模块名在点函数的方式。
Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中,而不是将指向整个模块
也可以导入多个模块
代码示例
from sys import path, argv
示意图
from…import… 导入示意图
- 执行 from time import sleep 语句相当于创建一个变量名 sleep 指向模块里面的函数名,也就是说调用当前文件里面的 sleep() 相当于调用了模块里的 sleep() 函数。
- 所以这种导入方式很容易造成名称冲突,如果我们在当前文件里面又定义了一个函数名叫 sleep ,那么就不能调用模块里的函数了。也就是示意图中的指向全部断了。
方式三 from...import *
代码示例
from time import *
sleep(5)
---from 模块名 import 模块里所有部分---
和方式二不同点就是模块里所有部分都被导入到当前文件的名称空间
示意图
from…import * 导入方式
但是也会造成名称冲突。
下划线禁止引用
我们向文件导入模块时,只能导入模块中名称不以单下划线'_'或双下划线'__'开头的变量、函数和类。因此
,如果我们不想模块文件中的某个内容被引入到其它文件中,可以在其名称前添加下划线。
代码示例
def __f1__():
pass
__all __ 属性
__all__ 属性用于 from 模块名 import * 方式导入模块时限制。
'被导入模块'若定义了__all__属性,则只有__all__内'指定的属性、方法、类可被导入'
定义的语法
__all__ = []
该变量的值是一个列表,括号里放模块中的变量、函数或者类的名称。
__all__ 变量仅限于在其它文件中以 from 模块名 import * 的方式引入。用其他的俩种方式引入模块时此属性不起作用。
修改模块名字
我们在使用模块的时候可以对模块进行重命名,这样不会混乱
代码示例一
import time as first
first.sleep(1)
在模块名后面加 as 后面跟重命名的名字。
代码示例二
from time import sleep as first
first(1)
在 from...import... 中也可以重命名,不过它是将具体的变量、函数或者类的名称重命名。
循环导入
循环导入就是俩个文件互相导入彼此,如下图所示
此时打印 b.py 中的 name 就会报错,因为 b.py 中代码还没有执行到定义 name
我们在使用模块的时候应该尽量避免出现循环导入的问题。
实在出现了,我们可以将导入模块的语句放在定义名称的代码后面。或者将导入模块的句式写在函数体代码内
判断文件类型
py 文件可以分为俩种类型,分别为:执行文件,被导入文件(也就是模块)。
被导入文件就是模块。
- 我们也可以写模块使用,当我们在编写模块内容的时候,测试代码是少不了的,但是怎么让测试代码不被别人使用呢?
- 例如在上图中,执行文件 a.py 中只导入了 b.py ,但是由于被导入文件中执行了函数,所以运行执行文件也会显示函数的内容。
内置变量__name__
内置变量__name__ 就可以实现区分被导入文件中的功能代码和测试代码
当__name__所在的文件是执行文件的时候 结果是__main__
当__name__所在的文件是被导入文件时候 结果是文件名(模块名)
1. 也就是说,'执行文件在调用被导入文件的时候',被导入文件中的__name__ 的值为被导入文件的模块名
我们可以利用这一区别特性来进行对测试代码和功能代码。
2. 我们在'被导入文件'中加一个 if 判断进行筛选
代码示例
if __name__ == '__main__':
'测试代码'
3.使用 if 判断之后,如果我们需要模块中进行测试,由于此时的 __name__ 为 __main__ ,所以 if 条
件为 True 。但是我们作为使用者调用了模块,在这个时候模块里的 __name__ 为 模块名,所以 if 条件
为False 。
在 pycharm 中直接输入 main 之后按 tab键 会自动生成该 if 判断。
模块的查找顺序
我们使用模块的时候也像找变量名一样有查找的顺序。
1.先从内存空间中查找
2.再从内置模块中查找
3.最后去sys.path查找(类似于我们前面学习的环境变量)
如果三个地方都找不到 那么直接报错
我们可以定义一个和内置模块 time 同名的模块 time ,然后在执行文件中导入模块 time 。
但是由于查找顺序内置模块更快一些,于是导入的是内置模块,也就是说不会造成名称冲突。
sys.path
代码示例
import sys
print(sys.path)
我们可以打印一下 sys.path ,会得到一个列表,列表里面是各种路径,当内存中和内置中都没有要查找的
模块时就会去列表里的路径中挨个查找
- 找不到模块:
sys.path 中的路径第一个就是当前执行文件所在的路径,在这个路径下的模块都会被执行文件找到,如果不在同一个文件下的模块,执行文件是找不到的,如图一所示此时因为找不到 c.py 程序会报错。
- 解决方式一:
解决方式一,在 sys.path 中添加路径,就像添加环境变量。由于 sys.path 打印的是一个列表,可以用列表的内置方法 append() 并在括号里添加需要导入的模块路径。如上图
- 解决方式二:
解决方式二,用 from…import… 语句来指名道姓的导入,如上图
- 解决方式二拓展:
如上图所示,若模块在多个文件夹里面,我们可以通过点文件名的方式找到其下面的多个模块
- 特殊情况
(1)如上图所示,在多个文件下的执行文件 c.py 中导入文件外面的模块 a.py ,按照上面写的如果不改变路径应该会出错。我们可以先打印 c.py 中的 sys.path ,我们会发现它里面有一个项目目录所在的路径,这路径是 pycharm 自动添加的。所以我们导入同在项目目录所在的路径下的 a.py 是不会报错的。(在终端中是不会自动添加的,会报错。)
(2) 同理,由于 pycharm 只自动添加了项目目录所在的路径,所以 c.py 调用别的文件夹中的模块例如 file_b 中的模块是找不到的。
绝对导入与相当导入
我们在前面的查找顺序中知道,导入模块的路径是按照执行文件的位置去查看的。
绝对导入
永远按照执行文件所在的路径一层层往下查找
相对导入
相对导入打破了必须参照执行文件的所在路径的规则,只需要考虑当前模块所在的路径然后使用特殊符号
'.'去查找其他模块即可'(只能在模块中使用,不能在执行文件中使用)'
我们首先了解一下 . 代表的含义
.表示当前路径
..表示上一层路径
../..表示上上一层路径
使用的方法
from . import 模块名
- 如上图所示,a.py 在项目目录下,b.py 和 c.py 在文件 file_c 中,首先我们在 a.py 中导入模块 b.py ,使用绝对导入的方式找到 b.py ,b.py 被执行。
- 在 b.py 中,又导入了模块 c.py 。如果我们使用 import c 语句导入的话,程序会报错,因为路径是根据执行文件的位置来寻找的,虽然这个语句在只单单运行 b.py 的时候不会出错。
- 那既然在执行文件中被引入的模块也引入了其他的模块(a 导了 b,b又导了c),在这种情况下除了绝对导入的方式还有一种导入方式(只能在模块中使用),使用符号
.
- 在前面我们了解了一个
.
表示的是当前位置,也就是说,这个导入的方式是按照使用了导入语句的文件的位置作为参照。而不是以执行文件作为参照。这样我们在像上图的情况也能实现像绝对导入一样的效果。
包
包其实可以看成是多个模块组成的文件夹,其内部包含一个叫做__init__.py
的文件才会被认作是一个包。(虽然在 python3 中可有可无,但最好还是留着。)
生成包的方式,我们可以在文件夹手动创建一个名 __init__.py 的文件,此时就会被转成包了,或者使用
pycharm 中自带的创建包的功能也可以。
__init__.py 的作用
在导入包的时候索要名字其实是跟包里面的__init__.py要,我们打印一下包名,会显示 __init__.py
如果想直接通过包的名字使用包里面所有的模块,那么需要在__init__.py中提前导入
- 我们创建一个包,里面包含
__init__.py
文件,我们如果在里面创建名称,那么我们在上图中 b.py 里面导入包名后是点不出内容的,因为包名相当于__init__
- 上图中在
__init__.py
中定义了变量 name 后,在 b.py 中就能点出 name 变量名。
在__init__.py
中将所有的模块事先导入,然后在执行文件 b.py 中执行导入语句from A import *
就可以使用包里模块名点方法的形式调用了。