这就是Python 模块
1. 模块简介
1.1 什么是模块
编写较长程序时,建议用文本编辑器代替解释器,执行文件中的输入内容,这就是编写 脚本 。随着程序越来越长,为了方便维护,最好把脚本拆分成多个文件。编写脚本还一个好处,不同程序调用同一个函数时,不用每次把函数复制到各个程序。为实现这些需求,Python 把各种定义存入一个文件,在脚本或解释器的交互式实例中使用。这个文件就是 模块
模块即是一系列功能的结合体。
1.2 为什么使用模块
提高了代码的可维护性,不用重复造 轮子 提升开发效率.
1.3 模块的各类
python
pip
1.4 模块的表现形式
- 使用python编写的代码(.py文件),就是平时写的一个python文件
- 已被编译为共享库或DLL的C或C++扩展
- 包好一组模块的包(文件夹)包其实就是多个py文件(模块)的集合包里面通常会含有一个 __init__.py 文件(在python3中这个文件可以没有)
- 使用C编写并链接到python解释器的内置模块
2. import句式
导入模块使用关键字 import 加 py 文件名,不要加 .py .
示例:
# 导入内置模块
>>> import time
>>> time.time() # 直接使用
1637651203.9467623
#导入自定义
# 代码文件:foo.py
name = 'Hans'
def hello(name):
print("Hello, %s" % name)
# 导入
>>> import foo
>>> foo.
foo.hello( foo.name
>>> foo.name
'Hans'
>>> foo.hello(foo.name)
Hello, Hans
>>> foo.hello("Jack")
Hello, Jack
# 同一个模块多次导入
# 代码文件:boo.py
print("hello")
# 导入
>>> import boo # 第一次导入,会执行里面的代码。
hello
>>> import boo # 第二次导入,不会执行
>>> import boo # 第二次导入,不会执行
>>> import boo # 第二次导入,不会执行
# 多次导入相同模块 只会执行一次
模块首次导入发生了什么?(以导入 boo.py 中导入 foo.py 为例)
# foo.py
name = 'Hans'
def hello(name):
print("Hello, %s" % name)
# boo.py
import foo
print("hello world")
foo.name
foo.hello(foo.name)
foo.hello("Jack")
# 执行结果:
hello world
Hello, Hans
Hello, Jack
- 运行导入文件( boo.py )产生该文件的全局名称空间
- 运行 foo.py
- 产生 foo.py 全局名称空间 运行 foo.py 文件内代码 将产生的名字全部存档于 foo.py 名称空间
- 在导入文件名称空间产生一个 foo 的名字指向 foo.py 全局名称空间
import 方法导入模块后就可以使用模块中的所有的变量名或函数名,而且绝对不会冲突,因为调用的时候已经指定了要使用哪个包中的那个变量或函数
3. from...import...句式
from...import... 句式为从哪个包或模块中导入哪个模块或功能。
示例:
# foo.py代码:
name = 'Hans'
def hello(name):
print("Hello, %s" % name)
def hi():
print("Hi, world")
# boo.py代码:
from foo import hi #在boo中只使用foo的hi功能
print("hello world")
hi()
# 执行结果:
hello world
Hi, world
# 代码 boo.py
from foo import hi
from foo import hi
from foo import hi
执行结果:
from foo
# from...import...多次导入也只会导入一次
使用 from...import... 导入:
- 先产生执行文件的全局名称空间
- 执行模块文件 产生模块的全局名称空间
- 将模块中执行之后产生的名字全部存档于模块名称空间中
- 在执行文件中有一个 hi 执行模块名称空间中 hi 指向的值
导入
# foo.py 代码
print("from foo")
name = 'Hans'
def hello(name):
print("Hello, %s" % name)
def hi():
print("Hi, world")
# boo.py 代码
from foo import hi
print("hello world")
def hi():
print("from boo hi")
hi()
# 执行结果:
from foo
hello world
from boo hi # 发现执行hi()的结果为boo.py中的函数不是从foo.py中导入进来的hi
from...import... 指定的导入某个名字
在使用的时候直接写名字即可 但是当前名称空间有相同名字的时候,就会产生冲突 使用的就变成了当前名称空间
4. 导入方式的扩展
4.1 使用别名
# import导入
>>> import foo as f # 把foo定义别名为f,这时只能调用f,如果再调用foo就会报错,说foo没有定义
>>> f.name
'Hans'
# from ... import ...导入
>>> from foo import hi as h # 把hi定义为别名为h,调用的时候直接使用h即可,同理hi也不能使用
>>> h()
Hi, world
4.2 连续导入
# import导入
>>> import sys
>>> import os
# 上面的导入方式可以写成下面:
>>> import sys, os # 这种方式和上面的方式功能是一样的
# from ... import ...导入
>>> from foo import hello
>>> from foo import hi
# 上面的导入方式可以写成下面:
>>> from foo import hello, hi # 这种方式和上面的方式功能是一样的
import 使用连续导入多个模块时,如果多个模块功能相似或者属于同一个系列时推荐使用。
如果功能不同并且不属于一个系列 那么推荐分行导入
4.3 通用导入
如果使用from ... import ...方式导入一个模块里全部功能时,最基本的方法是依次导入
>>> from foo import hello, hi, name
# 或
>>> from foo import hello
>>> from foo import hi
>>> from foo import name
#可以使用* 号把一个模块里的全部功能都导入
>>> from foo import *
# 如果一个模块里有三个功能,在使用from ... import ... 想让人用其中两个可以使用__all__
# 代码:
print("from foo")
name = 'Hans'
def hello(name):
print("from foo. Hello, %s" % name)
def hi():
print("from foo Hi")
def play():
print("from foo play")
__all__ = ['hi', 'play'] # 在被导入的模块文件中可以使用__all__指定可以被导入使用的名字
# 执行:
>>> from foo import *
from foo
>>> hi()
from foo Hi
>>> play()
from foo play
>>> hello("Hans")
Traceback (most recent call last):
File "", line 1, in
NameError: name 'hello' is not define
4.4 判断py文件是作为模块文件还是执行文件
可以使用函数自带的 __name__ 方法
# foo.py 代码
print("from foo")
name = 'Hans'
def hello(name):
print("from foo. Hello, %s" % name)
def hi():
print("from foo Hi")
def play():
print("from foo play")
print("__name__: %s" % __name__)
# 执行如果:
from foo
__name__: __main__
# 如果foo.py是直接执行时。__name__为 __main__
# 如果foo.py 当成模块在别的文件里导入时:
# importTest.py 代码
import foo
#执行结果:
from foo
__name__: foo
# 如果foo.py文件是被当做模块导入则返回模块名
#
# 一个py文件当成模块被导入时,它会直接执行py文件里的全部代码,可以利用__name__来判断它是否被当成模块导入,如果是则不执行
# 代码 foo.py
def hello(name):
print("from foo. Hello, %s" % name)
def hi():
print("from foo Hi")
def play():
print("from foo play")
if __name__ == '__main__':
print("from foo")
name = 'Hans'
# 代码 importTest.py
import foo
# 执行结果:
#之前导入的时候会直接打印: from foo
5. 模块导入的顺序
模块导入的顺序:
- 先从内存中查找
- 再去内置模块中查找
- 最后去sys.path系统路径查找(自定义模块)
如果都没有查找到则报错
# 1.在内存中查找
# foo.py 代码:
def hello(name):
print("from foo. Hello, %s" % name)
def hi():
print("from foo Hi")
def play():
print("from foo play")
if __name__ == '__main__':
print("from foo")
name = 'Hans'
# importTest.py 代码:
from foo import hello
import time
print("Hello")
time.sleep(10)
hello("time")
# 执行结果:
Hello
#在time.sleep(10)的时候把foo.py删除,这时foo.py已经加载到内存中,所以下面依然执行
from foo. Hello, time
#如果再执行则会报错
# 2.再去内置模块中查找
# 可以自己定义一个和内置模块同名的模块,看看导入的是谁
# 自己编写:time.py 代码:
print("time...")
# boo.py 代码:
import time
print(time)
# 执行结果:
# 发现time为内置的模块,所以在给py文件命名的时候不要与内置模块名冲突
# sys.path系统路径查找
>>> import sys
>>> sys.path
['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/local/lib64/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages/cloud_init-17.1-py3.6.egg', '/usr/lib/python3.6/site-packages', '/usr/lib64/python3.6/site-packages']
# ''为当前目录,然后依次查找
当某个自定义模块查找不到的时候解决方案:
1.自己手动将该模块所在的路径添加到sys.path中
# 查看当前目录
[root@hans_tencent_centos82 tmp]# pwd
/tmp
[root@hans_tencent_centos82 tmp]# python3
>>> import foo
Traceback (most recent call last):
File "", line 1, in
ModuleNotFoundError: No module named 'foo'
# 提示没有foo模块。
# 查找foo.py模块在哪
[root@hans_tencent_centos82 module]# pwd
/tmp/module
[root@hans_tencent_centos82 module]# ls -lrt foo.py
-rw-r--r-- 1 root root 202 Nov 23 16:54 foo.py
# foo.py在/tmp/module目录下。
# /tmp/module加入到sys.path
>>> import sys
>>> sys.path.append('/tmp/module')
>>> import foo
>>> sys.path
['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/local/lib64/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages/cloud_init-17.1-py3.6.egg', '/usr/lib/python3.6/site-packages', '/usr/lib64/python3.6/site-packages', '/tmp/module']
# 可以看到 '/tmp/module'添加到sys.path
2.使用 from...import... 句式
from 文件夹名称.文件夹名称 import 模块名
from 文件夹名称.模块名称 import 名字
# from 文件夹名称.文件夹名称 import 模块名
# foo.py在/tmp/module目录下。
# 当前目录为/tmp
# 使用from...import...
# 执行结果:
>>> from module import foo
>>> foo.hi()
from foo Hi
#当前在/tmp下,而foo.py在/tmp/module/test/下
[root@hans_tencent_centos82 tmp]# ls -lrt /tmp/module/test/foo.py
-rw-r--r-- 1 root root 202 Nov 23 16:54 /tmp/module/test/foo.py
>>> from module.test import foo
>>> foo.play()
from foo play
# from 文件夹名称.模块名称 import 名字
#只导入foo模块中的一个功能:
>>> from module.test.foo import play
>>> play()
from foo play
6. 循环导入
不允许出现循环导入
真要出现了,一般解决方法(就是明知道有循环导入了还是让它运行,一错再错方法):
- 调换顺序
将彼此导入的句式放在代码的最后 - 函数形式
将导入的句式放入函数体代码 等待所有的名字加载完毕之后再调用