程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

荐python学习笔记(八)包和库

发布于2020-03-12 12:36     阅读(1192)     评论(0)     点赞(5)     收藏(2)


 

目录

(一)何为包

(二)创建一个包

1)包内的__init__文件

2)mathproj包的基本用法

3)子包和子模块的加载

4)包内的import语句

5)all属性

6)包的合理使用

7)包总结

(三)Python库的使用


 

(一)何为包

模块可以让小块代码轻松得以重新利用。当项目不断壮大,就会出现多种问题,需要重载的代码在物理逻辑上都会超出单个文件的合理大小。解决这个问题的方案是把有关联的模块组合到同一个包中。

 

模块是容纳代码的文件,一个模块定义了一组Python函数和其他对象,通常这些函数和对象都是关联的。模块的名称由文件名称而来。

包就是包含代码和子目录的目录。包里包含了一组通常相互关联的代码文件(模块)。包的名称由主目录名而来。

包是模块概念的自然扩展,旨在应付非常大型的项目。模块把相互关联的函数、类和变量进行了分组,同理,包则是把相互关联的模块进行了分组。

 

 

Python搜索模块的路径是由四部分构成的:程序的主目录、PATHONPATH目录、标准链接库目录和.pth文件的目录,这四部分的路径都存储在sys.path 列表中。

 

在导入自定义的模块时,除了指定模块名之外,也需要指定目录,由于Python把目录称作包,因此,这类导入被称为包导入。包导入把计算机上的目录变成Python的命名空间,而目录中所包含的子目录和模块文件则对应命名空间中的属性。

Python已经导入的模块保存在一个内置的sys.modules字典中,以便记录哪些模块已经记录了。

如果想看模块搜索路径在机器上的实际配置,可以通过打印内置的sys.path列表来查看,这个列表是sys模块的path属性:

  1. >>> import sys
  2. >>> sys.path
  3. ['', 'D:\\python37\\Lib\\idlelib', 'D:\\python37\\python37.zip', 'D:\\python37\\DLLs', 'D:\\python37\\lib', 'D:\\python37', 'C:\\Users\\administrator\\AppData\\Roaming\\Python\\Python37\\site-packages', 'D:\\python37\\lib\\site-packages']

 

 

(二)创建一个包

这里用一个能够运行的例子来演示包机制的内部工作原理。文件名和路径将显示为普通文本,以便明确我们分析的是文件还是目录,还是由该文件/目录定义的模块/包。以下是这个mathproj包的树状结构图:

以下是这个包的代码:

  • mathroj/__init__.py文件
  1. print("Hello from mathproj init")
  2. __all__ = ['comp']
  3. version = 1.03
  • mathproj/comp/__init__.py
  1. __all__ = ['c1']
  2. print("Hello from mathproj.comp init")
  • mathproj/comp/c1.py
x = 1.00
  • mathproj/comp/numeric/__init__.py
print("Hello from numeric init")
  • mathproj/comp/numeric/n1.py
  1. from mathproj import version
  2. from mathproj.comp import c1
  3. from mathproj.comp.numeric.n2 import h
  4. def g():
  5. print("version is ",version)
  6. print(h())
  • mathproj/comp/numeric/n2.py
  1. def h():
  2. return "Called function h in module n2"

当我们把以上代码按照树状结构输入mathproj文件中后,还要确保mathproj在python的当前工作目录。

1)包内的__init__文件

以上代码中能发现,每个文件夹中都有一个__init__.py文件,这个文件有两个用途:

  • Python要求,只有包含__init__.py文件的目录才会被识别为包。这可防止意外导入包含其他Python代码的目录。
  • 当第一次加载包或子包时。Python会自动执行__init__.py文件。有了这种自动执行的机制,就能够完成任何必要的包初始化工作。

很多包都不需要在其__init__文件中写入任何内容,只要保证有个空的__init__.py文件就行了。

2)mathproj包的基本用法

当做好以上工作后,保证你的mathproj模块存在于你的IDLE模块检索路径之中时,在Python shell中执行以下语句:

  1. >>> import mathproj
  2. Hello from mathproj init
  3. >>> mathproj.version
  4. 1.03

如果一切顺利,Python将会执行__init__.py文件输出一段字符串,并且进入一个新的命令提示符,不会有错误信息。也就是说,第一次加载包的时候会自动执行__init__.py文件。

mathproj/__init__.py文件将把变量version赋值为1.03。变量version在mathproj包命名空间的作用域内,创建完毕后就可以通过mathproj访问,在mathproj/__init__.py文件之外也能够进行访问。

在使用过程中,包看起来与模块类似,都可以通过属性访问到其内部定义的对象。因为包就是模块的汇总。

3)子包和子模块的加载

mathproj包中的各个文件也是可以相互进行交互的。比如我们想访问mathproj/comp/nmeric/n1.py文件中定义的函数g,那么这个模块是否已经加载完毕了。上面已经导入了mathproj包,那么它的子包是否导入了呢:

  1. >>> mathproj.comp.numeric.n1
  2. Traceback (most recent call last):
  3. File "<pyshell#2>", line 1, in <module>
  4. mathproj.comp.numeric.n1
  5. AttributeError: module 'mathproj' has no attribute 'comp'

我们发现访问这个函数会进行报错,也就是说,只加载顶级模块是不够的,这并不会加载其全部子模块。这是符合Python理念的,即清晰比简洁更重要。

解决以上问题,只要导入所需模块即可,然后就可以执行该模块中的函数g了:

  1. >>> import mathproj.comp.numeric.n1
  2. Hello from mathproj init
  3. Hello from mathproj.comp init
  4. Hello from numeric init
  5. >>> mathproj.comp.numeric.n1.g()
  6. version is 1.03
  7. Called function h in module n2

不过这么导入的话,每一个包中的__init__.py文件都会被执行,每一个包都被导入,可以在其中产看上一级包的内存地址判断这个包是否被导入:

  1. >>> mathproj.comp
  2. <module 'mathproj.comp' from 'D:\\python37\\mathproj\\comp\\__init__.py'>
  3. >>> mathproj.comp.numeric
  4. <module 'mathproj.comp.numeric' from 'D:\\python37\\mathproj\\comp\\numeric\\__init__.py'>

4)包内的import语句

包内的文件不会自动获得包内其他文件的访问权限,无法访问同一包内其他文件中定义的对象。我们来看一下n1.py文件中:

  1. from mathproj import version
  2. from mathproj.comp import c1
  3. from mathproj.comp.numeric.n2 import h
  4. def g():
  5. print("version is ",version)
  6. print(h())

n1.py文件想要访问其他包和文件中的version以及h函数,需要先进行导入。

因为n2.py和n1.py位于同一个目录中,所以还可以使用相对导入的方式,只要在子模块名前加一个.即可。也就是n1.py的第三行写成这样,一样可以奏效:

from .n2 import h

5)all属性

一般来说,如果外部代码执行了from module inport *语句,就应该从mathproj导入全部的非私有对象名称。实际上着比较难以实现主要问题是,对于不容的操作系统来说,对文件名的定义规则比较含糊,这就导致了子包导入后其确切名称也含糊不定。

例如,写的是from mathproj import *,那么comp会被导入为comp、Comp还是COMP呢?如果只是依赖系统给出的名称,那么结果是不可预测的。

为了解决这个问题,Python引入了__all__属性,__all__属性应该给出一个字符串列表,定义了如果外部代码对这个包使用from module import *时,应该导入的名称。如果没有定义这个属性的话,我们在使用from module import *时,不会对该包执行任何操作。

我们在上面定义的包中输入以下语句:

  1. >>> from mathproj import *
  2. Hello from mathproj init
  3. Hello from mathproj.comp init
  4. >>> comp
  5. <module 'mathproj.comp' from 'D:\\python37\\mathproj\\comp\\__init__.py'>
  6. >>> c1
  7. Traceback (most recent call last):
  8. File "<pyshell#2>", line 1, in <module>
  9. c1
  10. NameError: name 'c1' is not defined
  11. >>> from mathproj.comp import *
  12. >>> c1
  13. <module 'mathproj.comp.c1' from 'D:\\python37\\mathproj\\comp\\c1.py'>

从上面的代码中能看出来,使用from module import *导入时,和前面import module语句一样的规则。

导入包时,只是对这个包的名称,而不会导入这个包里面的包的名称,要想得到这个名称也需要进行一次显式的导入。

6)包的合理使用

大多数包的结构,都不应该像以上例子暗示的那么复杂。有了Python包机制,包设计时的复杂程度和嵌套层次就能有很大的自由度了。

  • 包不应该采用嵌套很深的目录结构。除非代码量极其庞大,否则没有必要这样做。大多数包只需要一个顶级目录即可。两层目录结构就应该能有效处理绝大部分情况。正如Python之禅中所述“平直胜于嵌套”。
  • 只要不在__all__属性中列出,就可以用__all__属性对from module import *隐藏这些对象的名称。尽管如此,但这可能并不算是一种好方案,因为这会导致不同导入方式的结果不一致。如果需要隐藏对象名称,请用前导双下划线让他们称为私有对象。

7)包总结

1,包的初始化

Python在首先导入某个目录时,会自动执行该目录下的__init__.py文件中的所有程序代码。

2,模块命名空间的初始化

在包导入模型中,脚本内的目录路径,在导入后会变成真实的对象路径,即为目录创建的模块对象提供了命名空间。

3,from *语句的行为

在__init__.py文件内使用__all__列表,来定义目录以from * 语句形式导入时,需要导出的属性清单。如果没有设置__all__,from *语句不会自动加载潜逃与该目录内的子模块,也就是说,只加载该目录下的__init__.py文件中罗列在__all__列表中的变量。

注意以下几点:

  1. 有了包机制,就能够创建横跨多个文件和目录的代码库。
  2. 相比单个模块,利用包可以更好地组织大型的代码集。
  3. 除非真有庞大而复杂的库,否则包里嵌套的目录大于一或两层时就得当心了。

 

(三)Python库的使用

在Python中,所谓的库是由多个组件组成的,包括无须import语句即可使用的数值和列表之类的内置数据类型和常量,以及一些内置函数和异常。库中最大的部分就是大量的模块。只要安装了Python,就可以用库来操作各类数据和文件、与操作系统交互、为众多互联网协议编写服务端和客户端、开发和调试代码。

 

 

参考:

  1. 悦光阴

 

 

原文链接:https://blog.csdn.net/weixin_45755966/article/details/104084432



所属网站分类: 技术文章 > 博客

作者:我Lovepython

链接:https://www.pythonheidong.com/blog/article/254154/711e3170978f8601acf8/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

5 0
收藏该文
已收藏

评论内容:(最多支持255个字符)