美文网首页
18. Python之模块和包

18. Python之模块和包

作者: 随便写写咯 | 来源:发表于2021-02-02 22:02 被阅读0次

1 什么是模块

    模块就是一系列功能的集合体,分为三大类
        I:内置的模块(Python解释器提供)
        II:第三方的模块(其他人编写)
        III:自定义的模块(开发人员自己编写)
            一个python文件本身就是一个模块,文件名m.py,模块名叫m

            ps:模块有四种形式
              1 使用python编写的.py文件

              2 已被编译为共享库或DLL的C或C++扩展
            
              3 把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
            
              4 使用C编写并链接到python解释器的内置模块

2 为何要用模块

    I:内置与第三方的模块拿来就用,无需定义,这种拿来主义,可以极大地提升自己的开发效率
    II:自定义的模块
        可以将程序的各部分功能提取出来放到模块中为大家共享使用
        好处是减少了代码冗余,程序组织结构更加清晰

3 如何用模块(import导入模块)

  • foo.py模块文件
print("模块foo==>")
x=1
def get():
    print(x)
def change():
    global x
    x=0
  • 模块.py, 代码文件, 调用foo模块
y = 333
z = 444
import foo # foo这个名字属于模块.py这个文件的名称空间,指向的是foo.py模块文件的名称空间
# 执行模块.py文件后,会导入foo模块,然后会执行foo.py文件中的代码,因此,会在控制台输出以下内容
模块foo==>
1. 首次导入模块会发生3件事

1、产生foo.py文件的名称空间,将foo.py运行过程中产生的名字都丢到foo.py的名称空间中,本示例中,foo.py文件有x变量名,get和change函数名
2、执行foo.py内部代码
3、在当前文件(也就是调用foo模块的文件,这里就是模块.py文件)中产生的有一个名字foo,该名字指向1中产生的名称空间, 也就是foo.py文件的名称空间,另外还会产生本身该模块.py文件包含的名字,y和z
image.png
之后的导入,都是直接引用首次导入产生的foo.py名称空间,不会重复执行代码
import foo
import foo
import foo
import foo
2. 如何引用模块中的功能
# 模块.py
print(foo.x)
print(foo.get)
print(foo.change)
强调1:模块名.名字,是指名道姓地问某一个模块要名字对应的值,不会与当前名称空间中的名字发生冲突
x=1111111111111
print(x) # 1111111111111
print(foo.x) # 1
1
<function get at 0x0000018C348AB4C0> 
# print(模块.函数名字)返回的是该名字在模块的名称空间的内存地址, print(模块.函数名字())返回的是该函数的返回值
<function change at 0x0000018C34B66670>
强调2:
无论是查看还是修改,操作的都是模块本身,与调用位置无关
模块的名称空间查找关系以模块定义阶段的查找关系为准

# 模块.py
import foo

x=3333333333
foo.get() # 1
foo.change() # 没有结果,因为change函数没有print
print(x) # 3333333333
print(foo.x) # 0,该代码执行在了foo.change()后,因此,此时change函数内的global x,已经把x改为了0,所以结果为0
foo.get() # 0,再次执行结果为0,因为此时global的x已经被change函数修改为0了
3、可以以逗号为分隔符在一行导入多个模块
建议如下所示导入多个模块
import time
import foo
import m
不建议在一行同时导入多个模块
import time,foo,m
4、导入模块的规范
I. python内置模块
II. 第三方模块
III. 程序员自定义模块

 import time
 import sys

 import 第三方1
 import 第三方2

 import 自定义模块1
 import 自定义模块2
 import 自定义模块3
5. import ... as ...
 import foo as f # f=foo,别名,相当于把foo在调用文件的名称空间的内存地址给了f,通过f找到foo,再找到foo.py
 f.get()
6、模块是第一类对象
import foo
可以赋值, 可以当做函数的参数, 函数的返回值等, 和函数一样都是第一类对象
7、自定义模块的命名应该采用纯小写+下划线的风格
8、可以在函数内导入模块
def func():
    import foo
9、模块py文件存放位置

内置模块:由python解释器提供,py文件形式的内置模块会存到python解释器安装的路径下
对于Linux或者MacOS,路径案例:/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9
对于Windows,路径案例:C:\Users\David\AppData\Local\Programs\Python\Python36\Lib

第三方模块:一般通过pip下载
对于Linux或者MacOS,路径案例:/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages
对于Windows,路径案例:C:\Users\David\AppData\Local\Programs\Python\Python36\Lib\site-packages

对于虚拟环境,无论是哪个平台,以py文件形式存在的内置模块都存放在解释器安装的路径,不会专门复制一份,存到虚拟环境的目录中
而对于第三方模块,会单独存放在虚拟环境目录lib/site-packages,因为虚拟环境目的就是区分开不同项目的不同第三方模块

4. __name__变量

当一个python文件, 被当做模块导入时, __name__的值为模块名
当一个Python文件, 被运行时, 其值为'__main__'
用途: 当模块文件直接被当做程序运行时, 会运行其定义的代码, 而如果被导入其他文件时, 又不运行代码
用法: 判断__name__的变量值是否等于'__main__
foo.py
# coding:utf8
x = 10
def get():
    print('foo.py的get方法')

def change():
    print('foo.py的change方法')
    global x
    x = 20

if __name__ == '__main__':
    print('文件被执行')
    get()
    change()
else:
    print('文件被导入')
    pass
运行结果:
文件被执行 # 因为模块文件自身被运行时, 会运行if判断内的代码
foo.py的get方法
foo.py的change方法
code.py
import foo
运行结果:
文件被导入 # 被当做模块导入时, 不会运行if判断内的代码, 因为被导入时,__name__的变量值就是模块名本身

5. from ... import 导入模块

impot导入模块在使用时必须加前缀"模块."
优点:肯定不会与当前名称空间中的名字冲突
缺点:加前缀显得麻烦
from ... import ...导入也发生了三件事
产一个模块的名称空间
运行foo.py将运行过程中产生的名字都丢到模块的名称空间去
在当前名称空间拿到一个名字,该名字与模块名称空间中的同名的变量指向同一个内存地址
注意: 在模块的名称空间做的变量赋值引发的内存地址的改变, 是不会影响引用了该模块的py文件的自身的映射关系, 其内部还是只想定义阶段的内存地址, 除非重新导入模块, 刷新名称空间关系
from...impot...导入模块在使用时不用加前缀
优点:代码更精简
缺点:容易与当前名称空间混淆
foo.py
x = 1
from foo import x # x=模块foo中值1的内存地址
x=1111 # 执行了x=1111,就把当前空间的x指向了1111, 因此不指定模块前缀容易混淆
import vs from ... import
在code.py import 导入模块foo时, code.py调用foo.x, 那么x指向了foo名称空间中的x, 是和foo中的x要内存地址
而如果是from foo import x, 那么在code.py中, x就直接指向了foo中x的内存地址, 无需和x查询, 也就导致了, 直接修改foo中的x的内存地址, 是不会影响code.py中的x的内存地址的, 除非重新from导入一次foo模块
一行导入多个名字(不推荐)
from foo import x,get,change

*:导入模块中的所有名字(一般不推荐, 除非要导入的名字太多
name='admin'
from foo import *
print(name) # 此时, foo中如果有name, 那么name就指向了foo中name的内存地址了, 原先name会被覆盖, 容易造成混淆
每个模块都内置了__all__变量=[模块中的每个名字组成的列表], 因此, from ... import *时会导入模块中所有的名字
也就是说, __all__=[名字1,名字2,]可以用来控制, from ... import *时, 会导入的名字
可以把*代表的名字写到__all__里, 算上避免混淆的一个方法
from foo import get as g
print(g)

6. 模块查找优先级

无论是import还是from...import在导入模块时都涉及到查找问题
优先级:
1、内存(内置模块)
2、硬盘:按照sys.path中存放的目录的顺序依次查找要导入的模块

import sys
值为一个列表,存放了一系列的文件夹
其中第一个文件夹是当前执行文件所在的文件夹
print(sys.path)
sys.modules查看已经加载到内存中的模块
导入到内存中的模块, 只有在Python程序运行结束后才会被回收, 否则无论是del还是在函数内导入模块运行后都不会从内存中释放

6.1. sys.path的应用

import sys
# 找foo.py就把foo.py的文件夹添加到环境变量中, 不过要注意这是程序运行时, 临时修改环境变量
sys.path.append(r'foo.py在操作系统中存放的路径') # 将存放路径追加到sys.path的列表中
import foo

7. 包

7.1 包的介绍

1、包就是一个包含有__init__.py文件的文件夹
    
    
2、为何要有包
    包的本质是模块的模块的一种形式,包是用来被当做模块导入
导入包发生的事情:

1、产生一个名称空间
2、运行包下的__init__.py文件,将运行过程中产生的名字都丢到1的名称空间中
3、在当前执行文件的名称空间中拿到一个名字mmm,mmm指向1的名称空间
import mmm
print(mmm.x)
print(mmm.y)
mmm.say()
from mmm import x

7.2 包的绝对导入

环境变量是以执行文件为准备的,所有的被导入的模块或者说后续的其他文件引用
的sys.path都是参照执行文件的sys.path
包为foo
存放三个模块文件
图片.png
如何在程序中调用?
需要在__init__.py中导入包foo中的模块
__init__.py

# 导入包的方法
# 1 绝对导入: 以包的文件夹作为起始来进行导入, 这里就是foo, 但前提是foo所在的目录被加入到了sys.path环境变量, 否则找不动foo就更找不到包里的模块.
# 2 sys.path.append('foo所在路径')
from foo.m1 import f1
强调:
1.关于包相关的导入语句也分为import和from ... import ...
两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:
凡是在导入时带点的,点的左边都必须是一个包,否则非法。
可以带有一连串的点,如import 顶级包.子包.子模块,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
例如:
from a.b.c.d.e.f import xxx
import a.b.c.d.e.f
其中a、b、c、d、e 都必须是包


2、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间

3、import导入文件时,产生名称空间中的名字来源于文件,
import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件

7.3 包的相对导入


相对导入:仅限于包内使用,不能跨出包(包内模块之间的导入,推荐使用相对导入)
.:代表当前文件夹
..:代表上一层文件夹

from .m1 import f1
from .m2 import f2
from .m3 import f3
from .bbb.m4 import f4
强调:
1:相对导入不能跨出包,所以相对导入仅限于包内模板彼此之间

2:而绝对导入是没有任何限制的,所以绝对导入是一种通用的导入方式

相关文章

  • 18. Python之模块和包

    1 什么是模块 2 为何要用模块 3 如何用模块(import导入模块) 4. __name__变量 5. fro...

  • 核心开发

    Python核心开发 一.包和模块 1. 包和模块的定义 为了更加有好的对python代码进行管理,出现了包和模块...

  • python 2.7 -> python 3.7 升级记录

    更换的模块 python 3.7 模块名python 2.7 模块名python 3.7 包python 2.7包...

  • Python高阶

    包(lib)、模块(module) 在Python中,存在包和模块两个常见概念。 模块:编写Python代码的py...

  • Python常用模块

    Python常用模块之time模块 Python常用模块之os模块 Python常用模块之sys模块 Python...

  • 笔记:Python的包和模块的区别

    Python中的模块和包的英文表示: 模块的英文:Module 包的英文:Packages 对模块和包的类比理解:...

  • urllib

    python模块(包)之urllib urllib:官方文档是最好的模块表达说明。 urllib is a pac...

  • python学习(二)

    python模块和包 在文件系统中,python包就是文件夹,模块就是xx.py文件,包可以有多级 区分包和普通目...

  • socket

    python模块(包)之socket socket:官方文档是最好的模块表达说明。 socket 1、socket...

  • python 模块和包

    模块和包 目标 模块 包 发布模块 01. 模块 1.1 模块的概念 模块是 Python 程序架构的一个核心概念...

网友评论

      本文标题:18. Python之模块和包

      本文链接:https://www.haomeiwen.com/subject/yrrzaktx.html