python导入包相当于什么_Python包及其定义和引用详解
对于一个需要实际应用的模块而言,往往会具有很多程序单元,包括变量、函数和类等,如果将整个模块的所有内容都定义在同一个 Python 源文件中,这个文件将会变得非常庞大,显然并不利于模块化开发。
什么是包
为了更好地管理多个模块源文件,Python 提供了包的概念。那么问题来了,什么是包呢?
从物理上看,包就是一个文件夹,在该文件夹下包含了一个 __init__.py 文件,该文件夹可用于包含多个模块源文件;从逻辑上看,包的本质依然是模块。
根据上面介绍可以得到一个推论,包的作用是包含多个模块,但包的本质依然是模块,因此包也可用于包含包。典型地,当我们为 Python 安装了 numpy 模块之后,可以在 Python 安装目录的 Lib\site-packages 目录下找到一个 numpy 文件夹,它就是前面安装的 numpy 模块(其实是一个包)。该文件夹的内容如图 1 所示:
图 1 numpy 模块(包)的文件结构
从图 1 可以看出,在 numpy 包(也是模块)下既包含了 matlib.py 等模块源文件,也包含了 core 等子包(也是模块)。这正对应了我们刚刚介绍的:包的本质依然是模块,因此包又可以包含包。
定义包
掌握了包是什么之后,接下来学习如何定义包。定义包更简单,主要有两步:
创建一个文件夹,该文件夹的名字就是该包的包名。
在该文件夹内添加一个 __init__.py 文件即可。
下面定义一个非常简单的包。先新建一个 first_package 文件夹,然后在该文件夹中添加一个 __init__.py 文件,该文件内容如下:
'''
这是学习包的第一个示例
'''
print('this is first_package')
上面的 Python 源文件非常简单,该文件开始部分的字符串是该包的说明文档,接下来是一条简单的输出语句。
下面通过如下程序来使用该包:
# 导入first_package包(模块)
import first_package
print('==========')
print(first_package.__doc__)
print(type(first_package))
print(first_package)
再次强调,包的本质就是模块,因此导入包和导入模块的语法完全相同。因此,上面程序中第 2 行代码导入了 first_package 包。程序最后三行代码输出了包的说明文档、包的类型和包本身。
运行该程序,可以看到如下输出结果:
this is first package
==========
这是学习包的第一个示例
从上面的输出结果可以看出,在导入 first_package 包时,程序执行了该包所对应的文件夹下的 __init__.py;从倒数第二行输出可以看到,包的本质就是模块;从最后一行输出可以看到,使用 import
first_package 导入包的本质就是加载井执行该包下的 __init__.py 文件,然后将整个文件内容赋值给与包同名的变量,该变量的类型是 module。
与模块类似的是,包被导入之后,会在包目录下生成一个 __pycache__ 文件夹,并在该文件夹内为包生成一个 __init__.cpython-36.pyc 文件。
由于导入包就相当于导入该包下的 __init__.py 文件,因此我们完全可以在 __init__.py 文件中定义变量、函数、类等程序单元,但实际上往往并不会这么做。想一想原因是什么?包的主要作用是包含多个模块,因此 __init__.py 文件的主要作用就是导入该包内的其他模块。
下面再定义一个更加复杂的包,在该包下将会包含多个模块,并使用 __init__.py 文件来加载这些模块。
新建一个 fk_package 包,并在该包下包含三个模块文件:
print_shape.py
billing.py
arithmetic_chart.py
fk_package 的文件结构如下:
fk_package
┠──arithmetic_chart.py
┠──billing.py
┠──print_shape.py
┗━━__init__.py
其中,arithmetic_chart.py 模块文件的内容如下:
def print_multiple_chart(n):
'打印乘法口角表的函数'
for i in range(n):
for j in range(i + 1):
print('%d * %d = %2d' % ((j + 1) , (i + 1) , (j + 1)* (i + 1)), end=' ')
print('')
上面模块文件中定义了一个打印乘法口诀表的函数。
billing.py 模块文件的内容如下:
class Item:
'定义代表商品的Item类'
def __init__(self, price):
self.price = price
def __repr__(self):
return 'Item[price=%g]' % self.price
print_shape.py 模块文件的内容如下:
def print_blank_triangle(n):
'使用星号打印一个空心的三角形'
if n <= 0:
raise ValueError('n必须大于0')
for i in range(n):
print(' ' * (n - i - 1), end='')
print('*', end='')
if i != n - 1:
print(' ' * (2 * i - 1), end='')
else:
print('*' * (2 * i - 1), end='')
if i != 0:
print('*')
else:
print('')
tk_package 包下的 __init__.py 文件暂时为空,不用编写任何内容。
上面三个模块文件都位于 fk_package 包下,总共提供了两个函数和一个类。这意味着 fk_package 包(也是模块)总共包含 arithmetic_chart、 billing 和 print_shape 三个模块。在这种情况下,这三个模块就相当于 fk_package 包的成员。
导入包内成员
如果需要使用 arithmetic_chart、 billing 和 print_shape 这三个模块,则可以在程序中执行如下导入代码:
# 导入fk_package包,实际上就是导入包下__init__.py文件
import fk_package
# 导入fk_package包下的print_shape模块,
# 实际上就是导入fk_package目录下的print_shape.py
import fk_package.print_shape
# 实际上就是导入fk_package包(模块)导入print_shape模块
from fk_package import billing
# 导入fk_package包下的arithmetic_chart模块,
# 实际上就是导入fk_package目录下的arithmetic_chart.py
import fk_package.arithmetic_chart
fk_package.print_shape.print_blank_triangle(5)
im = billing.Item(4.5)
print(im)
fk_package.arithmetic_chart.print_multiple_chart(5)
上面程序中第 2 行代码是“import fk_package”,由于导入包的本质只是加载并执行包里的 __init__.py 文件,因此执行这条导入语句之后,程序只能使用 fk_package 目录下的 __init__.py 文件中定义的程序单元。对于本例而言,由于 fk_package\__init__.py 文件内容为空,因此这条导入语句没有任何作用。
第 5 行导入语句的本质就是加载并执行 fk_package 包下的 print_shape.py 文件,并将其赋值给 fk_package.print_shape 变量。因此执行这条导入语句之后,程序可访问 fk_package\print_shape.py 文件所定义的程序单元,但需要添加 fk_package.print_shape 前缀。
第 8 行导入语句的本质是导入 fk_package 包(也是模块)下的 billing 成员(其实是模块)。因此执行这条导入语句之后,程序可使用 fk_package\billing.py 文件定义的程序单元,而且只需要添加 billing 前缀。
第 11 行代码与第 5 行代码的导入效果相同。
该程序后面分别测试了 fk_package 包下的 print_shape、billing、arithmetic_chart 这三个模块的功能。运行上面程序,可以看到三个模块的功能完全可以正常显示。
上面程序虽然可以正常运行,但此时存在两个问题:
为了调用包内模块中的程序单元,需要使用很长的前缀,这实在是太麻烦了。
包内 __init__.py 文件的功能完全被忽略了。
想一想就知道,包内的 __init__.py 文件并不是用来定义程序单元的,而是用于导入该包内模块的成员,这样即可把模块中的成员导入变成包内成员,以后使用起来会更加方便。
将 fk_package 包下的 __init__.py 文件编辑成如下形式:
# 从当前包导入print_shape模块
from . import print_shape
# 从.print_shape导入所有程序单元到fk_package中
from .print_shape import *
# 从当前包导入billing模块
from . import billing
# 从.billing导入所有程序单元到fk_package中
from .billing import *
# 从当前包导入arithmetic_chart模块
from . import arithmetic_chart
# 从.arithmetic_chart导入所有程序单元到fk_package中
from .arithmetic_chart import *
该程序的代码基本上差不多,都是通过如下两行代码来处理导入的:
# 从当前包导入print_shape模块
from . import print_shape
# 从.print_shape导入所有程序单元到fk_package中
from .print_shape import *
上面第一行 from...import 用于导入当前包(模块)中的 print_shape(模块),这样即可在 tk_package 中使用 print_shape 模块。但这种导入方式是将 print_shape 模块导入了 fk_package 包中,因此当其他程序使用 print_shape 内的成员时,依然需要通过 fk_package.print_shape 前缀进行调用。
第二行导入语句用于将 print_shape 模块内的所有程序单元导入 fk_package 模块中,这样以后只要使用 fk_package.前缀就可以使用三个模块内的程序单元。例如如下程序:
# 导入fk_package包,实际上就是导入包下__init__.py文件
import fk_package
# 直接使用fk_package前缀即可调用它所包含的模块内的程序单元。
fk_package.print_blank_triangle(5)
im = fk_package.Item(4.5)
print(im)
fk_package.print_multiple_chart(5)
上面第 2 行代码是导入 tk_package 包,导入该包的本质就是导入该包下的 __init__.py 文件。而 __init__.py 文件又执行了导入,它们会把三个模块内的程序单元导入 tk_package 包中,因此程序的下面代码可使用 tk_package.前缀来访问三个模块内的程序单元。
运行上面程序,同样可以看到正常的运行结果。
python导入包相当于什么_Python包及其定义和引用详解相关推荐
- python标准类型内建模块_Python内建模块struct实例详解
本文研究的主要是Python内建模块struct的相关内容,具体如下. Python中变量的类型只有列表.元祖.字典.集合等高级抽象类型,并没有像c中定义了位.字节.整型等底层初级类型.因为Pytho ...
- python分析方向的第三方库_Python标准库与第三方库详解
干货大礼包!21天带你轻松学Python(文末领取更多福利) 点击查看课程视频地址 本课程来自于千锋教育在阿里云开发者社区学习中心上线课程<Python入门2020最新大课>,主讲人姜伟. ...
- python脚本运行时网络异常_Python中异常重试的解决方案详解
前言 大家在做数据抓取的时候,经常遇到由于网络问题导致的程序保存,先前只是记录了错误内容,并对错误内容进行后期处理. 原先的流程: def crawl_page(url): pass def log_ ...
- python数据清理的实践总结_python 数据的清理行为实例详解
python 数据的清理行为实例详解 数据清洗主要是指填充缺失数据,消除噪声数据等操作,主要还是通过分析"脏数据"产生的原因和存在形式,利用现有的数据挖掘手段去清洗"脏数 ...
- python爬虫多线程是什么意思_python爬虫中多线程的使用详解
queue介绍 queue是python的标准库,俗称队列.可以直接import引用,在python2.x中,模块名为Queue.python3直接queue即可 在python中,多个线程之间的数据 ...
- 基于python的随机森林回归实现_PYTHON | 随机森林实战(代码+详解)
大家好,我是菜鸟君,之前跟大家聊过R语言的随机森林建模,指路 R语言 | 随机森林建模实战(代码+详解),作为刚过完1024节日的码农算法工程师来说,怎么可能只会用一种语言呢?今天就来说说Python ...
- python源程序文件的扩展名_python程序文件扩展名知识点详解
python程序文件的扩展名称是什么 python程序的扩展名有.py..pyc..pyo和.pyd..py是源文件,.pyc是源文件编译后的文件,.pyo是源文件优化编译后的文件,.pyd是其他语言 ...
- python中values是什么意思_Python values()与itervalues()的用法详解
dict 对象有一个 values() 方法,这个方法把dict转换成一个包含所有value的list,这样,我们迭代的就是 dict的每一个 value: d = { 'Adam': 95, 'Li ...
- python for i in range(len())_Python for i in range ()用法详解
for i in range ()作用: range()是一个函数, for i in range () 就是给i赋值: 比如 for i in range (1,3): 就是把1,2依次赋值给i r ...
最新文章
- 远程拷贝代码 指定端口
- 多进程,守护进程,锁
- 将所有的表中,数值类型由char,varchar改为nchar,nvarchar 的存储过程
- 图论(二)--各种图介绍
- gradle安装及idea导入spring5.0x的源码
- Struts 学习笔记之ActionForm
- Git正解 脱水版 【10. 内部机制】
- On the eighth day
- MySQL 10060错误 解决方法
- 【嵌入式】STM32实现SPI双机通信的一些细节(2)片选总结
- 测试工作规范及岗位职责
- IT职场人生系列之二十三 知识体系(专家与杂家)
- 2017 计蒜之道 初赛 第一场 A 阿里的新游戏
- 网聊是不是就要劈腿上床?
- macOS系统下载和配置git教程
- HCIP第十天 交换第一天
- java聊天室测试_Java网络聊天室实训能力测试
- java 函数fun_c语言中fun用法详解_后端开发
- 游戏原创声音该如何鉴定呢?
- 无聊的时候写了个颜色识别算法,基于RGB颜色模型
热门文章
- python colormap函数_python-使用由x,y位置定义的rgb值创建colormap
- 基于长短读长和参考基因组的组装错误检测算法的研究
- 如何进行基因组组装?
- 第四章 遗传变异的分类
- Evaluation and Validation of AssemblingCorrected PacBio Long Reads for MicrobialGenome Completion
- html中hover有静止的命令,我可以通过JavaScript禁用CSS:hover效果吗?
- linux 后台运行jar包命令,Linux 运行jar包命令(Cent OS 7后台运行jar包)
- torch==1.1.0和torchvision-0.3.0安装
- 12.前K个高频元素---使用优先队列和哈希表解决
- 注册HttpSessionListener失效原因