python模块

什么是模块

模块是一系列功能体的集合,算是一种代码'封装'的方式。

python脚本文件本身就是一个模块,我们运行一个脚本文件就是在执行该模块里面的代码功能。

# python中有三类模块:
# 内置模块:python解释器自带的模块,直接使用
# 第三方模块:python社区伙伴们开源提供的python模块,需要下载后使用
# 自定义模块:自定义模块指的是我们自己编写的脚本文件,文件名就是模块名,如 get_sum.py,get_sum就是模块名

补充了解,模块的四种形式:

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

为何使用模块

唯一目的:提高开发效率

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

将程序模块化会使得程序的组织结构清晰,维护起来更加方便。


导入模块

使用模块前需要先导入模块,不管任何形式的模块使用前都需要先导入。

导入模块方式

# 导入模块的方式
- 方式1:import module_name
- 方式2:from modele_name import model_content1, modele_content2, ...
- 方式3:from model_name import *
- 方式4:import modele_name as nickname

# 导入位置
- 文件头:文件开头导入的模块属于全局作用域
- 函数内:函数内导入的模块属于局部的作用域

模块导入方式需要注意的事项

  • 方式1,使用方式1导入模块后,使用模块里面的名字,需要通过module_name.名字的方式使用内容。这种'指名道姓'的使用方式可以避免名字相同的冲突,但有时也很繁琐;
  • 方式2,方式2导入的名字可以直接使用,不用'指名道姓',但要注意命名冲突问题。
  • 方式3,方式3可以一次性导入模块下的所有名字。不常用,很容易产生命名冲突的问题。
  • 方式4,如果模块名很长,可以使用起别名的方式,简化模块使用的繁琐,还可以避免名字冲突问题。
# 方式2:无需加前缀的好处是使得我们的代码更加简洁,坏处则是容易与当前名称空间中的名字冲突,如果当前名称空间存在相同的名字,则后定义的名字会覆盖之前定义的名字。

# 方式3:只能在模块最顶层使用的方式导入,在函数内则非法。模块的编写者可以在自己的文件中定义__all__变量(一般是列表)用来自定义通过方式三导入时哪些名字能够被导入;还有,下划线开头的名字不会被*导入

#foo.py
__all__ = ['x','get'] # 该列表中所有的元素必须是字符串类型,每个元素对应foo.py中的一个名字
x = 1
def get():
    print(x)
def change():
    global x
    x = 0
class Foo:
    def func(self):
       print('from the func')
    
# 这样我们在另外一个文件中使用*导入时,就只能导入__all__定义的名字了


# 方式4,不仅可以简化代码,还可以保持调用方式的一致性,这一点很重要
if data_format == 'json':
    import json as serialize # 如果数据格式是json,那么导入json模块并命名为serialize
elif data_format == 'pickle':
    import pickle as serialize # 如果数据格式是pickle,那么导入pickle模块并命名为serialize

data = serialize.load(fn) # 最终调用的方式是一致的

导入模块规范

# 在文件顶部导入所有模块,一个模块占一行(虽然一行内用逗号隔开可以导入多个模块)

# 导入顺序: 每类模块间空一行, 且同类模块下按照模块名字母先后顺序排列
1 python内置模块
2 第三方模块
3 程序员自定义模块

# 模块名命名:模块名即python脚本文件名,和变量名命名规范一致。

使用模块

导入模块后,使用模块里面的名字的使用就和普通py文件一样,只不过我们使用的名字都是模块所在名称空间的。

无论是查看还是修改操作的都是模块本身,与调用位置无关

补充:模块也是python的一等公民,所以它和函数一样支持对象赋值,当参数、当容器类数据的元素等操作。


导入模块本质

第一次导入模块

# 1、产生一个新的名称空间(名字是被导入模块名);
# 2、执行被导入模块源文件代码,将产生的名字存放在新的名称空间中;
# 3、将模块名称空间的名字添加到当前执行文件所的名称空间中

# 补充:
- 导入方式:import ..,在当前执行文件的名称空间中放一个被导入模块的名字,通过这个名字引用模块中的名字。
-导入方式:from .. import..,在当前执行文件的名称空间中直接放一个模块中的名字,不能访问模块的其他名字。 

再此被导入

因为程序没有结束,第一次导入的模块已经在内存中,导入产生的名称空间也在内存中;
所以模块或模块中的名字再次被导入时,不会再运行模块文件的程序代码,而是从内存中直接绑定引用。

两种主要导入方式

import modeule 和 from modeule import name 几乎一模一样,发生的三件事一样。只是最后拿到的成功不一样,
# import module, 通过module.name的方式, 可以拿到module的所有名字;
# from module import name,每次只能拿到name,其他名字需要单独引入。

查找优先级

模块导入时的优先级

# 先后顺序:
	内存  --->   内置   ---->  sys.path路径
    
    
    
# 补充1:
import sys
sys.path是一个列表,里面存放各种文件夹的路径,当内存和内置中不存在需要导入的模块时,会在sys.path中找。
sys.path的第一个路径是当前执行文件所在文件夹的路径

# 补充2:
import sys
sys.modules 是一个字典,里面存放当前内存中已经有的模块,字典的键是模块名,对应的值是模块路径, 如:'m1': <module 'm1' from 'D:\\Oldboy\\day21\\m1.py'>}

py文件的两种用途

# 1 当脚本文件被执行
# 2 当模块被导入执行

# 区别:
	- 脚本文件执行时,产生的名称空间在程序运行结束后失效回收
    - 导入运行的文件产生的名称空间在引用计数为零时回收


# 补充:每个py文佳都有一个属性 __name__;
# 当py文件被当脚本执行时  __name__ == '__main__'
# 当py文件被当模块导入执行时,__name__ == '模块名'

模块导入循环

循环导入问题指的是在一个模块加载/导入的过程中导入另外一个模块,而在另外一个模块中又返回来导入第一个模块中的名字,由于第一个模块尚未加载完毕,所以引用失败、抛出异常。

究其根源就是在python中,同一个模块只会在第一次导入时执行其内部代码,再次导入该模块时,即便是该模块尚未完全加载完毕也不会去重复执行内部代码,只会在内存中找该模块,找不到就报错了。

解决该问题方案

# 方案1:将所有名字放到导入语句之前
# 方案2:只有某些函数时候导入模块时,将导入模块放到函数内

这种循环导入方式是不对的,是垃圾的,程序开发过程中应该时刻注意避免之。

编写模块规范

# 但我们编写模块共享时,需要情书表达模块的使用方式
# 文件都列出使用的模块,
# 尽量不要使用全局变量,
# 每个函数或类都写好说明文档
posted @ 2020-03-26 15:22  the3times  阅读(162)  评论(0编辑  收藏  举报