您好,欢迎来到网暖!

当前位置:网暖 » 站长资讯 » 建站基础 » 网络技术 » 文章详细 订阅RssFeed

Python模块化

来源:网络整理 浏览:276次 时间:2020-01-18
Python的包和模块module类型

在Python中,使用import关键字导入一个包或者模块,模块是一个名为module的类型,只有模块类型才可以直接使用import导入。首先是导包过程。

print('导入前:', dir())   # 导包前全局变量import osprint('导入后:', dir())   # 导包后全局变量-----输出结果-----#省略导入前:全局变量中没有"os"导入后:出现了"os"

这说明全局变量中出现了os标识符,这也是我们为什么可以使用os.chdir()等通过os标识符进行成员访问的原因。

再看一下os标识符的类型及os指向的这个对象。

print(type(os))print(type(os.path))print(global()["os"])  # 收集全局变量,查看os对象信息-----输出结果-----<class 'module'><class 'module'><module 'os' from 'E:\\Python\\lib\\os.py'>

上面结果显示osos.path是一个module类型,这也是os可以使用import导入的原因。只有module类型才能被导入。同理os.path也可以直接被导入。

print(dir())import os.pathprint(dir())-----输出结果-----#省略导入前:全局变量中没有"os" 或者 "os.path"导入后:出现了"os",但是没有"os.path"

os.path并不是一个合法的标识符(字符,下划线,数字),所以这个os.path对象没有被变量接受,但是我们之后需要能访问这个os.path对象 ,所以python为我们保留了os变量指向os模块。我们才可以使用os.path的方式访问。当然我们使用别名的方式os.path就可以被接收了。

import os.path as osposp.dirname(".")           # osp 即指向 os.path模块对象.调用它全局空间中的dirname(".")函数                   print(type(osp))           # <class 'module'>print(globals()["osp"])    # <module'ntpath'from'E:\\Python\\lib\\ntpath.py'>

osp直接指向了我们需要os.path模块,我们可以osp进行访问,os变量也就没有意义,所以此时的全局变量总并不存在os这个全局变量,但是os这个模块确实被import加载到内存空间中。只是在该模块中没有对应的表示符进行对应。

模块搜索顺序

sys.path中记录了模块的所有顺序,并且可以程序执行时候,导入了哪些类,所有被导入的类都会缓存在sys.modules中,调用即可查看。

import sysprint(*sys.path, "\n", *sys.modules, sep="\n")--------输出结果------'''D:\学习资料\练习项目\pycharm基础练习\myproject   # 当前路径D:\学习资料\练习项目\pycharm基础练习             # pycharm 创建的项目环境E:\Python\python36.zip                       # 以下为Python安装路径下的各个路径,可以为zip,egg文件E:\Python\DLLsE:\Python\libE:\PythonE:\Python\lib\site-packages'''{'builtins': <module 'builtins' (built-in)>,   # 已经被导入的各个模块信息'sys': <module 'sys' (built-in)>, 'os': <module 'os' (built-in)>, '_frozen_importlib': <module 'importlib._bootstrap'...'_tracemalloc': <module '_tracemalloc' (built-in)>, 'myproject': <module 'myproject' (namespace)>}

.egg文件是由setuptools库创建的包,第三方库常用的格式,添加了元数据信息的zip文件。

使用from导入

from ... import ...从一个模块中导入对象,这个模块可能是一个.py文件也可能是一个包(目录),导入的对象可以是包或者模块下的函数,类,模块等全局变量标识符,并且导入后可以直接使用import后的原变量标识符进行访问,而不需要加上模块前缀。fromimport后指定的内容都将被加载到内存。

from os import path          # 从os 导入 path模块,并可以使用path全局变量直接访问from os.path import dirname  # 从os.path 模块导入 dirname方法,可以直接通过dirname标识符访问该方法对象。from os.path import *        # 默认从os.path模块导入所有公共变量(非下划线开头),并直接使用原变量名作为该包下的全局变量

使用第三种方式容易造成该包中的全局变量被导入包中全局变量覆盖。除非清楚的知道两个包中的变量不会重名,否则尽量不使用。

使用 from ... import *默认导入的是公开变量(非___打头的变量),非公开变量导入必须手动才能访问,或者添加到all属性中才能使用*导入

from os import _abc, __abc   # 直接指定可导入,* 默认不含该类属性
__all__

在被导入模块中,可以添加__all__属性来指定该模块默认的全部可向外导出的模块。配合from ...import * 使用。__all__属性是一个字符串列表,这些字符串必须与该全局空间中的全局变量名对应,或者与该包下的子包名对应。

__all__ = ["x", "y", "_z"]x = 1y = 2z = 3_z = 4 

这个包被其他包使用 *导入时,导出__all__中对应的x, y,_z变量,实现了我们手动控制变量的导出。

包导入时属性优先,没有这个属性才会判断是否有这个模块。所以如果属性名和模块名冲突,该模块将无法再被导出。

Python中的包就是一个文件夹,文件夹下放各个模块的.py文件或者一个子包,方便管理。在包上也是可以写代码,这就是需要这个包下的__init__.py文件,这个文件属于这个包,当我们仅仅导入一个包时候,就是导入这个包下的__init__.py文件中的全局变量所指定的内容。并不会自动的导入这个包下的子模块。

包文件和模块文件

包模块的代码托管到包下的__init__.py文件中,即使包没有__init__文件仍然可以被导入,但并没有导入任何内容,这种情况下只能通过这个包名去寻找这个包下的模块文件。使用from ... inport ...导入子模块中的内容。

包是一个稍微特殊的模块对象,包的属性有['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__'],根据__package__属性可以判断它是否是一个包,该属性为None或者不存在表示不是包。

包下的模块为这个包的子模块,他们之间可以通过package.mod_name进行访问,前提是这个模块已经被导入,可以使用from package import mol_name或者import package.mol_name进行导入,两种导入效果相同,只是导入空间的变量名不同,使用形式不同。但是只import package无法自动导入它的子包,package.mul_name将不能访问。

相对导入和绝对导入

使用import导入模块顺序在sys.module记录,默认优先从执行文件的当前目录中寻找,无法找到再去Python安装文件中的库中寻找。这是一种绝对路径导入。

相对导入通常在一个包中使用,方便的将包中的各个模块进行关联,这种关联只受包内文件的相对位置约束,然而对于一个包我们通常不会去干涉内部的文件关系。相对导入原则遵循文件系统使用原则,即使是包__init__.py文件,这时属于这个包下的一个子文件,等同于这个包下的其他子文件。

符号示例..m当前文件夹中的m模块....m上一级文件中的m模块......m上上一级文件中的m模块
from .m import a     # 将会在当前目录下找 m 文件并导入afrom ..m import a    # 访问该文件的上一层目录找 m 文件并导入afrom .m.m1 import a  # 当前文件所在目录中的m包下的 m1文件并导入a

以上导入方式只能在包中使用,(任何一个相对导入的路径不能涉及主包所处的当前目录)这些文件不能作为主模块直接运行,它是一种包内部的关系的建立方式,直接运行将报错。

命名空间

当我们导入一个模块时,我们可以访问这个模块是因为在当前的作用域内部,创建了一个与模块名同名的全局变量,才可以通过这个全局变量对这个模块进行访问。所以我们是否能使用一个模块,需要两个条件:

  • 1、该模块被加载到内存中
  • 2、可以找到一个标识符直接和这个模块对象关联或者可以通过其他标识符的成员访问方式访问到这个模块对象。

不同的导入文件方式在这个命名空间中创建的标识符是不同的

import os        # 只导入os模块(os下的__init__.py中的内容),创建os标识符import os as o   # 只导入os模块,创建o标识符import os.path   # 同时导入os 和 os.path,只创建 os标识符,指向os模块。os.path可访问import os.path as osp  # 同时导入os 和 os.path,只创建 osp标识符,指向os.path模块,os模块在内存,但是无法访问,无标识符from os import path   # 同时导入os 和 os.path,只创建path标识符,指向os.path。os无法访问,无标识符from os import *      # 同时导入os中所有公开变量,如果有__all__属性,导入指定的内容,创建所有 * 指代的标识符,不会创建osform .m import a   # 在包内导入, m 和 a 均导入,m标识符可能存在,可使用 dir查看确认再使用,a 标识符存在
自定义模块

模块命名规范:
在导入模块时,会使用模块名作为标识符,这就要求模块名满足标识符的命名规范,这样才可以被导入。并且模块一帮使用小写字符,可以使用下划线分割。

模块重复导入

模块被加载一次后会在内存中缓存这个模块对象,这个模块的辨识信息被缓存到sys.modules中。导入模块时候,首先是从sys.modules中查询该模块是否已经被加载,如果已存在,并不会从文件中读取,而是直接使用内存中已存在的这个模块对象,否则import会IO搜索该模块的文件,编译,执行这个模块并加载大内存。

缓存的模块被保存在sys.module中,包括自己,其中还包括解释器运行需要的模块。
自定义模块a/b/c路径,如果只导入a模块import a,直接使用a.b是有风险的,该模块没有被加载,只有使用import关键字时,解释器才会模块进行加载,而不会自动的加载。

模块运行

当我们执行一个.py文件,此时解释器会启动去执行,但在执行这个文件之前,解释器还需要其他的工作,比如导入一些包,例如io,将我们的.py文件读入内存,或者build-in,因为我们可能使用到了这个内建函数。还有其他很多准备流程,当这个工作完成后,才会执行我们自己的.py文件。而这个.py文件也会被命名为__main__包。查看这个模块名,显示为__main__

print(__name__)       # __main__

除解释器执行的代码外,这个模块将会作为最外层的代码块,这个模块的结束代表该线程的结束。也被称作顶层代码。顶层代码包的"name"属性为__main__,其余模块的__name__属性为模块名。所以测试代码通常这样写

if __name__ == "__main__":    # test code   

只有这个模块直接执行时,if 中的测试代码才会执行。

推荐站点

  • 腾讯腾讯

    腾讯网(www.QQ.com)是中国浏览量最大的中文门户网站,是腾讯公司推出的集新闻信息、互动社区、娱乐产品和基础服务为一体的大型综合门户网站。腾讯网服务于全球华人用户,致力成为最具传播力和互动性,权威、主流、时尚的互联网媒体平台。通过强大的实时新闻和全面深入的信息资讯服务,为中国数以亿计的互联网用户提供富有创意的网上新生活。

    www.qq.com
  • 搜狐搜狐

    搜狐网是全球最大的中文门户网站,为用户提供24小时不间断的最新资讯,及搜索、邮件等网络服务。内容包括全球热点事件、突发新闻、时事评论、热播影视剧、体育赛事、行业动态、生活服务信息,以及论坛、博客、微博、我的搜狐等互动空间。

    www.sohu.com
  • 网易网易

    网易是中国领先的互联网技术公司,为用户提供免费邮箱、游戏、搜索引擎服务,开设新闻、娱乐、体育等30多个内容频道,及博客、视频、论坛等互动交流,网聚人的力量。

    www.163.com
  • 新浪新浪

    新浪网为全球用户24小时提供全面及时的中文资讯,内容覆盖国内外突发新闻事件、体坛赛事、娱乐时尚、产业资讯、实用信息等,设有新闻、体育、娱乐、财经、科技、房产、汽车等30多个内容频道,同时开设博客、视频、论坛等自由互动交流空间。

    www.sina.com.cn
  • 百度一下百度一下

    百度一下,你就知道

    www.baidu.com