在同一级目录下新建 p1.py 和 run.py,添加代码

# p1.py 模块的设计者
def f1():
print("from f1") def f2():
print("from f2") def f3():
print("from f3") # run.py 模块的使用者
import p1 p1.f1()
p1.f2()
p1.f3()

假设后期需要添加许多功能,可能添加的功能与已有的功能之间还有关联,这对于模块的设计者是很不方便的,于是设计者创建多个文件,把相关的功能放入同一个文件,这里我添加m1.py,m2.py,m3.py,将f1,f2,f3分别放入相关的功能文件

# m1.py
def f1():
print("from f1") # m2.py
def f2():
print("from f2") # m3.py
def f3():
print("from f3")

但这样对于使用者来说又不方便了,原先的使用方式固然已经改变,于是新建一个p1的文件夹,将m1.py,m2.py,m3.py放入p1,这样对于使用者看起来还是只有一个模块,使用的时候还是p1.f1(),p1.f2(),p1.f3()等

以前导入的p1是一个模块,现在导入的 p1 是一个文件夹(包),于是现在的问题是将这个包能够像之前的模块一样能够被导入和使用

一、什么是包

包就是一个包含有 __init__.py 文件的文件夹,本质就是一种模块,即包是用包导入使用的,包内部包含的文件也都是用来被导入使用

二、为何要用包

包是文件夹,那文件夹就是用来组织文件的

三、包的使用

首次导入包,发生三件事:

  1、以包下的 __init__.py 文件为基准来产生一个名称空间

  2、执行包下的 __init__.py 文件的代码,将执行过程中产生的名字都放入名称空间中

  3、在当前执行文件中拿到一个名字,该名字就是指向__init__.py 名称空间的

注意:

  1、在python3中,即使包下没有 __init__.py 文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错

  2、创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块

新建包 p1 和 run.py,在包下新建 m1.py,在 m1.py 中添加代码

# m1.py
def f1():
print('m1.f1')

现在我想在 run.py 中通过 p1.f1() 调用到 m1 中 f1 的功能,但此时是调用不到的,因为通过 p1 调用 f1 就是通过 __init__.py 调用 f1,__init__.py 中是没有 f1 的,f1 是在 m1 中,所以要在 __init__.py 中导入 m1,首先不能直接 import m1,因为还需要拿到 m1 下的 f1 功能,于是可能有人会想,那我直接 from m1 import f1 就行了,但这样也是不行的,因为内存中没有 m1,内置模块也没有 m1,于是在 sys.path 中查找,sys.path 是以执行文件是 run.py 为准,run.py 的 sys.path 的第一个值是上一级目录,这个目录中并没有 m1 模块(m1在p1中),所以直接 from m1 import f1 报错

又有人会想,那我把 m1 模块所在的文件夹(p1)添加到 sys.path 不就行了,于是我在 run.py(sys.path是以执行文件是run.py为准)中添加环境变量

import sys
sys.path.append(r'E:\Python\p1') import p1
p1.f1()

这样做确实能够实现在 run.py 中通过 p1.f1() 调用到 m1 中 f1 的功能,但是这对于使用者来说是很不方便的,每次都要添加内部功能所在文件夹的环境变量,所以这样做也是不合适的。

可以在 __init__.py 中以 p1.m1 的方式导入 f1,这样在 run.py中就可以直接导入 p1 然后 p1.f1() 执行

# __init__.py

from p1.m1 import f1

# run.py

import p1
p1.f1()

假设 run.py 和 p1 不在同一级目录下,现在我新建一个 dir1,在 dir1 下新建一个 dir2,将 p1 放入 dir2,那这时在执行 run.py 时,就需要在 run.py 中添加环境变量了,有人可能有疑问,上面不是说添加环境变量不方便使用者吗,注意,我在这里添加的环境变量不是 p1 内部功能所在文件夹的环境变量,而是找到 p1 所在文件夹的环境变量,这就相当于用户下载这个程序自己选择的保存位置,在这个位置下可以找到 p1。所以我在这里只需将 dir2 的位置添加到环境变量即可

# run.py

import sys
sys.path.append(r'E:\Python\dir1\dir2') import p1
p1.f1()

上面的导入也称之为绝对导入,每次都是参考执行文件的 sys.path 开始去导入 

软件每次更新都有不同的版本,设计者也需要将包改名,例如 p1_v1,p1_v2 等,如果使用的是绝对导入,那包内其它的导入都需要改变一次,所以包内的模块不应该使用绝对导入,应该使用相对导入

所以,在本片博客开始留下一个问题,将包像模块一样能够被导入和使用,于是在 p1 下新建一个 __init__.py 文件,使用相对导入

# __init__.py
from .m1 import f1
from .m2 import f2
from .m3 import f3

然后直接在 run.py 中导入 p1 便可以模块一样被使用

# run.py 模块的使用者
import p1 p1.f1()
p1.f2()
p1.f3()

现在我在同一级目录新建一个包 p1 和 run.py,在 p1 下新建包 p2,m1.py 和 m2.py,在包 p2 下新建 m3.py

  

# m1.py
def f1():
print('m1.f1') # m2.py
def f2():
print('m2.f2') # m3.py
def f3():
print('m3.f3')

现在还是想实现与博客开始相同的功能,通过 p1.f1(),p2.f2(),p3.f3() 访问功能,做法也与上面的相同,在 p1 的 __init__.py文件中导入相关模块即可

# p1的__init__.py

from .m1 import f1
from .m2 import f2
from .p2.m3 import f3

现在我想在 m3.py 的 f3 中访问到 f1 和 f2,于是在 m3 中需要导入 m1 和 m2

# m3.py

from ..m1 import f1
from ..m2 import f2 def f3():
print('m3.f3')
f1()
f2()

这时候即便 p1 改名 p1_v1,在 run.py 中导入调用 f3,包内的导入也无需改名

# run.py

import p1_v1
p1_v1.f3()

总结:

  1. 无论是 import 形式还是 from...import 形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法,点的左边都必须是一个包

  2、包的本质就是一个包含 __init__.py 文件的目录,导入包就是在导包下的 __init__.py 文件

  3、如果使用绝对导入,绝对导入的起始位置都是以包的顶级目录为起始点。但是包内部模块的导入通常应该使用相对导入,用一个点代表当前所在的文件(而非执行文件),两个点代表上一级,需要强调的是,相对导入只能在包内部的模块之间互相导入使用,使用多个点往上查找时不能超出顶级包

Learning-Python【17】:包的导入使用的更多相关文章

  1. 第10.9节 Python子包的导入方式介绍

    在<第10.8节 Python包的导入方式详解>详细介绍了包的导入方式,子包也是包,子包的导入与包的导入方法上没有本质区别,但二者还是有所不同.本节对照二者的方式介绍子包与包导入的关系: ...

  2. python 的包的导入

    已经写过一篇包的导入了,最近又遇到了点问题,所以想把这些再搞的明白点就又试了试 代码结构如下 在test目录下,有Admin包,home包,在home下有它的子包foo 各个文件代码如下 admins ...

  3. 7行代码,彻底告别python第三方包import导入问题!

    最近有不少小伙伴咨询关于pyton第三方包导入的问题,今天我们就来聊聊第三方包导入那些事. 随着对python学习的渐入臻境,越来越多的小伙伴们开始导入自己所需的第三方包,实现各种各样的功能.但是,他 ...

  4. linux下 彻底修改python的包/模块导入路径

    python模式下,有时候需要导入  import某些模块或者包.明明这个模块/包是存在的,却提示导入错误,比如,“ImportError: No module named lxml”. 但是当你在命 ...

  5. python基础===包的导入和__init__.py的介绍

    转自:https://www.cnblogs.com/botoo/p/8241522.html 调用同级目录: – src |– mod.py |– test.py 若在程序test.py中导入模块m ...

  6. python导包

    我们将完成特定功能的代码块放在一个.py结尾的文件中,这个文件被称为模块.在这个模块中可能包含变量,函数,类等等内容. 当我们从外部需要用到这个模块时,就需要将这个模块导入到我们当前环境.导入方式有以 ...

  7. python之模块、包的导入过程和开发规范

    摘要:导入模块.导入包.编程规范 以My_module为例,My_module的代码如下: __all__ = ['name','read'] print('in mymodule') name = ...

  8. python模块与包的导入

    1. 模块与包的区别 模块,即module,一个包含python语句的.py文件就是一个模块!每个源代码文件都会自动成为模块!没有额外的语法用来声明模块. 包,又称模块包,即module packag ...

  9. python中的模块,以及包的导入的总结

    模块导入的方式: 模块的概念:一个.py文件就称为一个模块 导入模块中函数的方式: 方式一:import  模块名 使用时:模块名.函数名() 方式二 :from 模块名 import  函数名 使用 ...

  10. python基础(12)-包的导入&异常处理

    包的导入 几种导入方式 import 包名 import time time.time() import 包名,包名 import time,sys time.time() sys.path from ...

随机推荐

  1. windows 安装 Apache、php、mysql及其配置(转载)

    此文包括的注意内容:软件版本及下载地址Apache2.4的配置和安装php7.0的配置mysql5.5的安装常见问题及解决方法1.软件版本Windows server 2008 r2+ 64位Apac ...

  2. CF2A Winner

    题目描述: 在 Berland 流行着纸牌游戏 “Berlogging” ,这个游戏的赢家是根据以下规则确定的:在每一轮中,玩家获得或失去一定数量的分数,在游戏过程中,分数被记录在“名称和得分”行中, ...

  3. vue脚手架---vue-cli

    开年第一篇 今天先讲一讲 vue-cli的安装 npm install vue-cli 可能需要很多的时间视网络环境而定, 如果长时间等待 也可以试试使用淘宝的镜像(cnpm)安装( npm inst ...

  4. oracle 数据库、实例、服务名、SID

    参考:http://www.zhetao.com/content240 在实际的开发应用中,关于Oracle数据库,经常听见有人说建立一个数据库,建立一个Instance,启动一个Instance之类 ...

  5. 20175320 2018-2019-2 《Java程序设计》第4周学习总结

    20175320 2018-2019-2 <Java程序设计>第4周学习总结 教材学习内容总结 本周学习了教材的第五章的内容.在这章中介绍了子类与继承,着重讲了子类继承的规则以及使用sup ...

  6. [本体论][UML][统一建模语言][软件建模][OWL]从本体论到UML到OWL

    以下内容,是关于软件建模的方法与思路. UML与OWL都是基于本体论的建模语言. 本体论(哲学) 本体论(信息科学) UML(统一建模语言) more info 参考:[设计语言][统一建模语言][软 ...

  7. MySQL 添加索引,删除索引及其用法

    一.索引的作用 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,所以查询语句的优化显然是重中之重. 在数据 ...

  8. tomcat配置内存

    windows: Create a new script named as setenv.bat under TOMCAT_HOME/bin folder holding the following ...

  9. 6.1-uC/OS-III软件定时器

    1.软件定时器是 uC/OS 操作系统的一个内核对象,软件定时器是基于时钟节拍和系统管理创建的软件性定时器,理论上可以创建无限多个,但精准度肯定比硬件定时稍逊一筹. 2.软件定时器启动之后是由软件定时 ...

  10. 016-并发编程-java.util.concurrent.locks之-Lock及ReentrantLock

    一.概述 重入锁ReentrantLock,就是支持重进入的锁 ,它表示该锁能够支持一个线程对资源的重复加锁.支持公平性与非公平性选择,默认为非公平. 以下梳理ReentrantLock.作为依赖于A ...