:Python项目组织结构-第一节:包模块以及__init__.py文件
Posted 快乐江湖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了:Python项目组织结构-第一节:包模块以及__init__.py文件相关的知识,希望对你有一定的参考价值。
文章目录
本章主要叙述Python项目的组织结构,这一章内容非常重要(很多人学完Python之后竟然连模块的含义都解释不清)
大型的、复杂的软件项目是不可能只用一个.py
文件就完成的,就像人员组织一样,它是由很多复杂的模块构成的。
一:Python项目组织结构
(1)Python项目组织结构
- 以下说法其实并不准确,但是在很多情况下我们都是这样理解的(说白了就是他们在你眼中展示的样子)
Python项目的组织结构从上至下依次为:
- 包(package):只要文件目录下,包含
_init_.py
这个空文件,Python解释器就会认为这个目录是一个包。这就是包和文件夹的显著区别 - 模块(module):任意一个
*.py
的Python脚本文件就是一个模块 - 类(class):面向对象思想,而且建议一个模块只包含一个类
- 函数、变量
(3)包与模块的作用
在python交互式解释器中操作输入的代码,在退出python时是不会被保存的; 而模块文件中的代码是永久存在的。减少重复代码, 减少工作量(写的量、改的量)、代码更优雅、拿来主义
- 比如数据分析经常会用到的,Numpy、Pandas等,这些模块中的代码我们也是可以实现的(难度很大),但不如直接用现成的方便
(2)包与模块的名字
不同的包下面可以有相同名字的模块,区别他们时使用“包名.模块名”
二:导入模块
因此,要使用其他模块内的变量或方法时,就需要导入相应模块,并且在引用时也要以“模块名.变量名”或“模块名.方法名”的方式引用
(1)import
import导入模块格式如下
import module1[, module2[,... moduleN]
如下,在p1.py
文件中有变量a = 10
;同时,test.py
文件和p1.py
处于同一包内,所以这里很容易导入
如果test.py
文件和p1.py
不在同一包内呢?如下,此时导入时就要以“包名.模块名”的方式导入了,同时使用时也要以“包名.模块名.变量名”或“包名.模块名.方法名”的方式使用
当模块嵌套过深时,引用变量就会变得很臃肿,此时可以使用import...as...
语句进行命名,这样在引用时就可以直接使用别名了
(2)from…import
Python 的 from...import
语句让你从模块中导入一个指定的部分到当前命名空间中,import
后面可以是变量、方法或者是模块
如果在import
后面跟上通配符*
,那么就会把模块中所有内容导入
但是这种方式缺陷也很大,因为导入时十分不明确。因此在这种情况下,我们可以使用模块内置属性__all__
,去设定被导入模块在被导入时哪些变量可以被导入
- 关于模块的内置属性在后面会细谈
例如,如果只想要变量a
和c
在遇到通配符*
时被导入,那么在该模块最前面加入
__all__ = ['a', 'c']
执行后会发现,变量a
和c
正确打印,但变量b
却显示异常
三:init.py文件
(1)作用
Python的包下面有一个特殊__init__.py
文件,它的作用有点像构造函数(类在被实例化时自动调用)。具体来说就是,当一个包被导入时,会自动执行__init__.py
文件
这里我们可以验证一下,具体流程如下
test.py
文件和包one
平级的,包one
下面有__init__.py
文件和p1.py
文件- 在
__init__.py
文件中加入a = "this is a __init__文件"
并打印 - 然后在
p1.py
文件中给变量b
赋值为10 - 最后在
test.py
文件中导入p1.py
并打印b
- 你会发现不止变量
b
被打印了,而且__init__.py
中的a = "this is a __init__文件"
也被打印了 - 这表明在包被导入的时候,
__init__.py
会自动执行
(2)使用场景
①:前面说过,__all__
可以决定本模块内的那些变量被导出,同样,__all__
如果放置在__init__.py
文件中就可以决定本包内哪些模块被导出
这里可以验证下,流程如下
__init__.py
文件中不写任何东西- 包
one
下面的p1.py
和p2.py
中分别有变量a=10
和变量b=20
- 在
test.py
文件中写入from one import *
表示导入包one
下的所有模块 - 然后执行,你会发现无法打印
- 此时如果在
__init__.py
中加入__all__ = ['p1']
,就表示只把p1.py文件导入 - 执行后你会发现结果和预期设想的一样
②:__init__.py
也经常会用于批量导入包。有的时候有些模块是要经常使用的(比如一些常见的Python内置库),在这种情况下,如果在每个文件中都重复写一遍,难免繁琐,所以可以把这些需要重复导入的模块的语句放置在一个包的__init__.py
中, 之后想要使用时,只需要导入该包即可
- 引用时,注意命名空间
四:关于包和模块一些注意点
- 如果之前没有任何编程语言基础,那么对这一部分你可能会感觉很乱,而且这部分也经常会导致一些错误发生
①:包和模块不会被重复导入
②:避免循环导入
下面就是一个循环导入的例子,执行p1
时遇到了import p2
,进入p2
后又遇见了import p1
,然后又进入p2
。这样就形成了循环
③:模块被导入时模块里面的语句是会被执行的
- 这一点很多人没有注意到
- 这一点其实经常用于入口文件
以上是关于:Python项目组织结构-第一节:包模块以及__init__.py文件的主要内容,如果未能解决你的问题,请参考以下文章
翻译:《实用的Python编程》09_01_Packages
Python模块详解以及import本质,获得文件当前路径os.path.abspath,获得文件的父目录os.path.dirname,放到系统变量的第一位sys.path.insert(0,x)