python笔记系列-day14 模块和包的使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fk002008/article/details/85335573

目录

回顾

模块和包

模块是包的属性

实验

from 包 import 模块

模块属性访问控制

模块中的共有项目和私有项目

私有被隐藏了还是不能访问

模块的FUNCTIONS 描述 - help 函数

下滑线命名对模块导入可见性

使用  import 模块  看不了私有属性但是可以访问

from 模块 import 私有属性   可以导入可以使用

from 模块 import *  无法访问私有属性

下滑线命名总结

from ... import *  

*的意义

__all__列表指定的访问控制

__all__列表指定和下划线命名规则不会结合

__all__列表对模块导入可见性

包属性访问控制

将模块的属性导入到包空间中

包的空间属性控制就是通过__init__.py来管理

实验

包空间-导入模块的属性-下划线命名

包空间-导入模块的属性 __all__列表使用

from 包 import * 总结

通过 包.模块.属性访问

sys.modules 字典

区分当前作用域

模块的__name__属性

将模块作为程序运行

模块的测试

安装模块


回顾

到此我们已经知道了python的面向对象支持方法以及如何组织我们的程序。

对于模块的理解现在也只是局限于 功能的封装,借助C的头文件帮助理解

对于包可以借助Java的包来帮助理解,还都很浅显,相信随着后面继续使用的深入,我们的理解会更加深刻

这也是我们 封装运用的基础,一定要好好掌握日后才可以自由的进行封装粒度的把控。

模块和包

包和模块的工作方式类似,但是内部的工作方式不同。

模块是一个py文件,封装着一些python功能

包是一个文件夹目录,里面含有一堆Py文件来共同完成一个大的目标

其中的控制就在  __init__.py 文件

一旦建立了包,那么模块就可以认为是包的属性了,

因此  就有了  from  包名  import 模块名  的使用了

模块是包的属性

模块是包的属性,因此可以使用  from 包名 import 模块名

这个和一般的从模块导入属性是类似的

比如我们之前写的  MyPack 模块,里面有classInfo.py 和 study.py 两个模块

我们如果直接进行这两个模块的导入看看有什么问题:

实验

我们从包的目录  D:\Apl\python_work\basic  进入到python 环境,此时直接导入包那么肯定会报错

因为我们的__init__.py文件中导入了 两个模块,导入模块一定要该模块的路径能被搜寻到

因此模块的路径必须要在  sys.path中

导入包报错

将__init__.py中导入的模块路径加入sys.path

现在模块的路径已经在  sys.path中了,按道理我们是不是可以直接导入模块了

我们发现是可以导入的,但是 我们之前的确是先导入包了,__init__.py 文件被导入了会不会有影响

我们另外打开一个dos窗口,先加入模块路径,但是不导入包,直接导入模块看看啥情况

也是可以导入的

from 包 import 模块

模块属性访问控制

模块中的共有项目和私有项目

那么什么是公有的呢?

1.如果模块定义了__all__列表,那么解释器使用__all__列表里面的内容确定哪些是公有项

2.如果没有定义__all__,那么解释器导入除了以下划线_开头的项目之外的所有项目

    如 clac是公有的,但是 _calc不是

私有被隐藏了还是不能访问

java中是否被隐藏是通过访问控制进行的,私有的方法外部是点不出来的。

而且该类暴露给外部的api是看不到私有的属性的

那么python呢?  help 查看模块是看不到私有属性的api,但是我们自己如果看代码知道属性的话可以使用

也就是语法上并没有强制我们不能使用,仅仅是作为旁观者不知道有这个属性不能使用

如果说真正被隐藏也只针对  import * 这一种导入方式有影响

我们按照上面说的命名规则 下划线 来看看:

模块的FUNCTIONS 描述 - help 函数

我们可以使用 

help(模块)  来查看一个模块内部的功能属性

这个函数结果中的FUNCTIONS 描述就是我们暴露被外部的api

下滑线命名对模块导入可见性

如下面的moduleTest.py  该模块定义了三个函数

其中只有这个 display函数不是下划线开头命名的

使用  import 模块  看不了私有属性但是可以访问

我们导入这个模块看看它有什么输出:

我们发现只有这个  display 被输出了,其他两个函数是没有被输出的

然后我们使用这个模块里私有的属性

from 模块 import 私有属性   可以导入可以使用

上面我们是import 的模块   import  模块  之后 是不影响我们使用 私有属性的,仅仅是api看不到而已

现在我们 直接  使用  from 模块 import 私有属性看好看

from 模块 import *  无法访问私有属性

下面直接导入  moduleTest 中的 所有元素,发现 _开头的是无法导入进来的

下滑线命名总结

通过上面的实验我们知道:只有  from 模块  import * 的时候 , 下划线的属性是无法导入到当前的命名空间中的

但是  import  模块  和  from 模块 import 属性 这两种方式都是可以访问的.

那么为什么  import * 不能呢?

from ... import *  

*的意义

其中 的 *  表示 告诉python 解释器导入模块的全部 公有方法,因此 只有满足模块中公有项目的定义表才可以被导入

如果使用 from 包名 import * 时候,这个*可不是都可以导出的,需要显示指定希望得的名称

出现在__all__列表中的所有名称也仅仅是这些名称可通过 * 导出

或者是下划线以外命名的情况

__all__列表指定的访问控制

借助模块文件的__all__列表 来指定这个模块中可以被导出的属性

我们将之前的 moduleTest.py 文件修改,加入 __all__指定

__all__列表指定和下划线命名规则不会结合

有__all__列表存在,按照__all__列表指定控制公有私有,此时的下划线命名规则失效

我们先 将原有的私有属性  _action 给加入到 __all__列表中

但是之前 符合公有的 display 不加入,我们查看一下模块的 function

发现  display 没有出现,如果有__all__列表 那么完全按照  __all__列表的指定来控制

同时多出来一个  DATA 的说明项目

__all__列表对模块导入可见性

通过上面下划线的实验呢我们知道 私有项目只对这个 import * 有影响

对于其他两种的没有影响.

那么 __all__列表一样,也只对  import * 产生影响

我们再将 display  也加入到 __all__列表,然后使用  import * 就可以访问这个 display了

包属性访问控制

前面我们看到了模块属性访问控制,公有和私有 对于 导入可见性

私有项目只有 import * 是不可见的.

那么包下面的属性如何控制呢?

模块就是包的属性, 包通过 __init__.py 来管理 模块的

__init__.py 本身就是一个模块文件

因此可以使用  __init__.py 里面的 __all__列表来进行管理的

对于包而言,模块本身就是包的属性

将模块的属性导入到包空间中

模块里面的属性我们可以通过  from 模块 import 属性 将模块的属性导入到包的空间中

那么包的属性可见性 就是包空间中的属性可见性访问控制

包的空间属性控制就是通过__init__.py来管理

由于 __init__.py本身就是模块文件,因此可以理解为是 __init__.py 属性访问可见性

这个就和之前的模块一样了

实验

我们用之前的 MyPack 模块来看下

首先在classInfo 模块中加入一个 以下划线开头的类_innerInfo  作为下滑线命名的属性

MyPack 包下面的 __init__.py文件中先不用__all__列表

但是我们要将 包下面模块的属性导入到 包空间中,因此  __init__.py 中的导入要修改下

包空间-导入模块的属性-下划线命名

根据__init__.py充当 管理模块的概念我们知道 包空间中的  下划线开头的名字属性

被认为是 私有的无法通过 import * 导入到当前空间中

这个和模块的导入可见性是一致的

包空间-导入模块的属性 __all__列表使用

我们修改下  __init__.py 文件 增加 __all__列表

from 包 import * 总结

通过对比我们发现,只有 import * 才有真正上私有的可见性问题

包的属性要通过  __init__.py 文件来进行管理,在该文件中 要把模块的属性导入到包的空间中

这样包空间就对这些模块的属性起了约束作用。

实际可用理解为 是 __init__.py 这个管理模块 起作用了

from 包  import * 最终 将包空间中的属性导入到了 当前的空间中

和 from 模块 import * 不同的就是  包空间要先将 模块属性导入到包空间中

模块属性------>  __init__.py -------> 当前空间

这样我们就可以直接在当前空间中访问 包下面模块中的属性了

通过 包.模块.属性访问

前面我们讨论的可见性都是 对于  import * 这种而言的

但是我们 如果不使用这种方式 导入  使用限定名称访问是没有问题

包括 包也一样

可以通过  包.模块.属性 的方式来进行访问的

sys.modules 字典

sys.modules 字典包含了目前已经导入的全部模块

sys.modules.keys 返回的列表就是已经加载过的每个模块的名称

区分当前作用域

模块 ,包 ,以及当前运行空间组成了不同的作用域

对于 属性的导入 的可见性我们要知道当前作用域是啥

模块的__name__属性

__name__属性可以告诉你 正在运行作用域的名称

比如 在模块中 检查 __name__属性的时候,返回的字符串就是这个模块名

经常可以在 模块中看到  if __name__ =='__main__'

__name__属性指明了 当前模块的属性名称

还有 如果我们在模块最后一行 写上  上面代码 表明 上面的模块代码可以通过执行的

将模块作为程序运行

模块本身就是一个py文件,当然可以在里面写一些可执行的代码

但是python给模块定义了一个约定,当一个模块自己运行时它应该执行模块测试

因此如果当前是在运行模块

if __name__== '__main__'

tset()

这种情况需要调用模块的测试

模块的测试

可以针对一个模块文件写一个测试模块文件

或者在原先的模块文件中 定义 test函数来进行测试

安装模块

python解释器在sys.path变量中列出的目录进行模块的查找

sys.path 包含当前目录,所以总是可以使用当前路径中的模块

但是如果我们想要在多个系统中使用模块的时候,需要将模块安装到sys.path变量列出的

某个目录下

大多数情况下,需要将python模块放到 site-packages目录中

除了模块还可以创建模块的包

包是一个安装到相同目录结构的相关模块的集合

猜你喜欢

转载自blog.csdn.net/fk002008/article/details/85335573