python模块和包
1.深入理解python库
库Library:一种对特定功能集合的通俗说法
- 包含一些程序功能,通过import引入使用,对应模块和包。
- 标准库:Standard Library,与python解释器一同安装的库。
- 第三方库:Third-Party Library,需要额外安装的库。
模块Module:以单个文件为命名空间的代码片段
- 模块是一个单独的.py文件,模块名就是文件名。
- 模块本质是一个独立的、由模块名组织的命名空间。
- 模块中可以引入其他模块,并由一些python语法来约束和管理。
包Package:由一组模块构成、有层次命名空间的程序功能
- 包由多个模块(多个.py文件)有组织的构成。
- 模块的组织方式构成了命名空间的层次结构。
- 包是模块的上一级组织概念,其中可以包括子包。
模块是一切库的基础单元
- 包由模块构成,可以理解为:包是目录,模块是.py文件。
- 库是通俗说法,具体指python的模块和包。
- python库的核心是模块及模块的组织方式(体现为命名空间)。
模块是一个命名空间
- 模块对应单独的.py文件,它是一个独立的命名空间。
- 模块内可能包含:类、函数、语句(直接可执行)、变量等元素。
- 模块内还包括一些其他对模块进行约束和管理的语法元素。
module_var=1
class module_class:
mc_classattr=1
def __init__(self,mc_instattr=1):
self.mc_instattr=mc_instattr
def mc_fun(self):
return "Method with a count of {}".format(self.mc_classattr)
def module_func():
print("Module Function")
print("Module Statement")
#命名为m.py
- 模块的调用
import m
print(m.module_var)
mc=m.module_class(99)
print(mc.mc_func())
m.module_func()
#<模块名>.<名称>
#访问模块内顶层命名空间的变量,类和函数。
'''
输出为:
Module Statement #当使用import调用m模块,m模块中的所有语句会被执行一遍
1
Method with a count of 1
Module Function
'''
from m import *
print(m.module_var)
mc=m.module_class(99)
print(mc.mc_func())
m.module_func()
输出为:
'''
Module Statement
1
Method with a count of 1
Module Function
'''
- 我们在名字前增加一个下划线
_module_var=1 #加一个下划线
class module_class:
mc_classattr=1
def __init__(self,mc_instattr=1):
self.mc_instattr=mc_instattr
def mc_fun(self):
return "Method with a count of {}".format(self.mc_classattr)
def _module_func():
print("Module Function")
print("Module Statement")
#命名为m.py
'''
此时我们用import m的方式依然可以调用
但是当我们用from m import *程序运行会报错
'''
模块是一个命名空间
- 模块中语句:在import时一次性执行。
- 模块内的变量、类和函数:在import时采用<模块名>方式可访问。
- 单下划线的顶层命名元素:不会在from … import * 时被导入。
包是一个有层次的命名空间
- 每个包需要包含一个__init__.py文件表达包的组织。
- _ _ init _ _.py可以是空文件,即,文件存在即可。
- 每个包可以嵌套包含更多子包。
- 通过包的组织可以形成由英文句号(.)分隔的层次化命名空间。
- _ _ init _ _.py用来构成包的定义,区分于包含.py文件的普通目录。
- 包、子包和模块可以用import 进行导入或单独导入。
模块的名称属性
名称属性:表达模块名称的预定义变量
属性 | 描述 |
---|---|
_ _name _ _ | 模块或包的名字,例:m. _ _ name _ _ |
def _module_func():
print("Module Function")
module_var=1
print("Module Statement")
print(__name__)
'''
Module Statement
__main__
'''
import m
'''
输出为:
Module Statement
m
'''
- 当程序以脚本方式直接执行时,_ name _的值为‘ _ _ main _ _’。
- 当程序以模块方式被引用时,_ name _ 的值为模块名称。
- 作用:区分程序以何种方式执行。
def _module_func():
print("Module Function")
if __name__=="__main__":
module_var=1
print("Module Statement")
print(__name__)
'''
Module Statement
__main__
'''
import m
'''
无输出
'''
if _ _ name _ _ == ’ _ _ main _ _ ’ :
- 当程序以脚本方式执行时,后续代码可以执行,否则不执行。
- 作用1:作为模块主体功能的单元测试部分。
- 作用2:作为模块内部保留的额外功能部分。
模块和包的构建
模块的构建
- 功能闭包:单一.py文件实现单一且完整的功能。
- 抽象适度:用函数或类进行抽象,结合功能选择合适抽象。
- 操作闭包:模块无顶层可执行语句,导入时无输出。
模块的构建原则
- 功能闭包:功能定义要清晰、设计要合理(紧耦合vs松耦合)。
- 抽象适度:采用类或函数,尽量选择一种;多种也无妨。
- 操作闭包:采用 _ _ name _ _ ,无全局可执行语句,尽量无全局变量。
"这是模块描述" #第一行增加描述
class module_class:
mc_classattr=1
def __init__(self,mc_instattr=1):
self.mc_instattr=mc_instattr
def mc_func(self):
return "Method with a count of {}".format(self.mc_classattr)
if __name__='__main__':
import sys
mc=module_class(sys.argv[1])
print("Module Statement") #顶层功能的引用放在__name__后
#dir()函数:以列表形式返回模块所使用的命名。
import m
print(dir(m))
包的构建
- 常规包:Regular Packages,通过 _ _ init _ _.py对文件和目录组织形成的包。
- 命名空间包:Namespace Packages,由更分散子包组成的包。
- 子包的位置可以再文件系统中不连续。
- 子包可以是压缩文件或网络连接或其他系统资源。
常规包
- 连续目录空间表达的、有层次的命名空间。
- 每个目录中包含一个 _ _ init _ _ .py,可以是空文件。
- 当包/子包被导入时,对应目录的 _ _ init _ _.py文件将被执行。
- 每个包仅被导入一次,且包导入按照层次结构进行。
- 直接导入包不行,需要进行到模块层次。(import pkg.pkg1包)
- from … import …直接导入具体模块,可以简化调用时命名空间表达。
(但是from … import * 需要额外代码的编写。)
_ _ all _ _ 属性
- from…import * 形式需要在 _ _ init _ _.py文件中增加 _ _ all _ _属性赋值。
- _ _all _ _ 需要被赋值为列表对象,包含当前包下所有希望被导入的模块名称。
- _ _ all _ _ 用来辅助导入模块,但不能辅助导入列表。
__all__=['m1','m2']
#在__init__.py中写入,再使用from ... import *就可以了。
命名空间包
命名空间包:表达命名空间层次结构的一种逻辑包形式
- 命名空间中各部分可以在不同的文件系统位置。
- 命名空间中各个子包并不包含__init__.py文件(普通目录!)
- python解释器通过sys.path变量来隐式维护命名空间包。
import sys
sys.path+=['project1','project2']
import pkg1.m1
import pkg1.m3
pkg1.m1.mecho(123)
pkg1.m3.mecho('python')
print(pkg1.__path__)
sys.path:指定搜索路径的字符串列表
- 指定import时搜索模块或包的路径列表,路径是相对或绝对路径。
- sys.path是一个列表类型,可以sys.path.append(p)增加新路径p。
- 载入后,根据其中包的名称和层次结构自然组成了命名空间包。
_ _ path _ _ 属性
- 记录了某个包(命名空间)的绝对或相对路径,列表类型。
- 常规包:路径是单一的,列表中只有一个元素。
- 命名空间包:路径是多元的,列表中可能有多个元素。
import系统:扩展命名空间及功能的方法
- 构成:import保留字、_ import _()函数和importlib标准库
- 步骤:模块的查找、模块的加载
- 价值:import系统是python代码复用和命名空间管理的精髓。
- import保留字:调用 _ import _进行模块查找,以及模块的加载。
- _ import _ ()函数:模块的查找,建立模块对象。
- importlib标准库:与import系统相关的丰富API。
万物皆对象:模块被导入后成为了对象
- 模块的对象形式:模块在程序中使用都是以对象形式体现的。
- 类似类对象,模块对象只有一个。
- 模块对象生成时,模块中代码会被执行,因此会有类对象产生。
模块的查找
查找路径:1.sys.modules
- 第一步查找sys.modules,之前被引入模块的缓存(cache)。
- sys.modules是一个字典,<模块名/对象引用>:<加载路径>。
- 如果模块不再sys.modules中,则进入下一步。
查找路径:2.查找策略
- 用户通过import钩子扩展的查找模式。
- 内置模块的路径。
- sys.path(列表变量)提供的加载路径,可以是zip文件或URL。
import钩子:import hook
- 扩展查找模块的方式:meta_path方式和import路径方式。
- meta_path:将查找方法增加到sys.meta_path列表变量。
- import路径:将查找方法注册到sys.path_hooks列表变量。
建立模块对象的过程
- 找到模块后,如果模块对象存在,则使用现有模块对象。
- 创建一个新的模块对象,将其加入sys.modules。
- 在程序当前命名空间执行模块代码。
- 创建对象:importlib.abc.loader.create_module()
- 执行对象:importlib.abc.loader.exec_module()
模块对象的命名空间
- 模块的命名空间与引用位置有直接关系。
- 如果引用在文件顶层,则使用文件顶层命名空间访问模块。
- 如果引用在非顶层,则使用局部命名空间访问模块。
import的三种使用方式
- import <模块名>
- from <模块名> import <类、函数名、*>
- import <模块名> as <别名>
import <模块名>
- 当前命名空间下的一个子命名空间。
- 成功加载后,产生一个与<模块名>同名的<模块对象名>。
- 实际上:<模块对象名>.<子命名空间内元素>方式访问。
from <模块名> import <类、函数、*>
- 将导入元素加载到当前命名空间下。
- 成功加载后,产生类对象或函数对象,覆盖同名对象。
- 实际上:<类对象名>或<函数对象名>方式访问。
import <模块名> as <别名>
- 当前命名空间下的一个子命名空间。
- 成功加载后,产生一个与<别名>同名的<模块对象名>。
- 实际上:<模块对象>.<子命名空间内元素>方式访问。
python第三方库的发布
发布前的准备
- PyPI:python package index,用来登记第三方库信息。
- Github、bitbucket:存储第三方库源代码及文档。
- 目标:通过pip进行安装和管理、源代码和文档网络可管理。
一些基本概念
- 项目project:pypi上一组发布和文件的统称。
- 发布release:项目的一个特定版本,每个发布有一个确定的版本号。
- 文件file:即package,一次发布包含的具体文件。
-
更新setuptools、wheel、twine工具。
-
注册pypi账户。
-
第一步:整理目录结构。
-
第二部:创建其他文件(setup.py:配置发布信息的文件,很重要。README.md:markdown格式的说明文件。LICENSE:版权声明文件。)
-
第三部:执行打包命令(python setup.py sdist bdist_wheel)
-
第四部:执行发布命令(twine upload dist/*)
-
打包发布:对文件整理打包后进行发布。
-
源发布:发布源代码的方式。
-
可执行发布:发布编译后可执行代码的方式。