.pyc文件还原.py文件_闲话python 43: 聊一聊__init__.py文件

最近在使用django开发一个网站项目,刚开始创建的数据库模型都在一个models.py文件中,等到模型较多以后就显得非常不方便,不仅是逻辑组织不清晰,修改代码也要找很久。这时就有一个需求,即创建一个名为models的python包,然后在包内分文件组织模型。但是要求对包外的所有调用与之前的models.py没有差异,否则修改外部调用的代码也是一件非常头疼的事情。这种情况下的需求可以抽象为使用python包模块提供与python文件模块同样的操作接口

在开发稍微复杂一点的python项目中,这种需求都是会经常遇到的,而对于一个python开发者而言,掌握这种需求的实现方式也是非常必要的。虽然大多数的开发者可能并不需要在自己的项目中这样操作,但是在调用一些第三方库的时候,却是常常遇到这种设计并受益匪浅。这种需求的实现方式的关键就是__init__.py文件。这个文件对使用python的朋友应该是再熟悉不过,因为我们常常遇到需要在目录中添加这样一个诡异的空文件,否则就会报错。本文就讨论一下python中的__init__.py文件在组织python包时的作用。本次实验需要创建一些目录和文件,方便起见,创建本次实验代码的根目录,然后加载到环境变量的path中,如下演示。

cd15f20af0b2020bfa2a34338c3377fe.png

创建根目录和加环境变量

1. python包由__init__.py定义

在使用python2的时候,我们被教导需要在作为python模块的目录中放置一个__init__.py文件,否则python解释器不会将该目录视为python模块,而对于这种目录的import操作都会报错。因此__init__.py文件是python包的定义,当然如果使用python3.3或更高版本的朋友会提出质疑。下面我们就看一下在python2.7与python3.7中的演示。

97702ca49dd92c94c92fadf45259e66d.png

python3.7导入目录

0a8e418ef8e1d3b7a60ee88ec428d52c.png

python2.7导入目录

从以上演示可以看出,在python2.7的实例中,没有__init__.py文件的目录在import的时候就报错了,错误原因是没有该名字的模块。而在python3.7中存不存在这个文件对python包的导入没有影响。事实上从python3.3开始就不需要使用__init__.py文件来定义python包了。这样说来,如果所使用的python版本在3.3以上是否就不需要再使用__init__.py文件呢?从实现的角度而言,确实如此,因为可以使用import直接导入包内部所需的功能模块。但是,对于为外部调用提供方便以及实现python包替换python文件模块的需求而言,__init__.py文件仍然是必要的,而且还需要在其中添加一些内容。

2. __init__.py为空或非空的区别

如果只是将一个目录作为组织python代码的过渡,而不需要将其作为python包,那么使用空的__init__.py文件或者不要这个文件都是可以的。如果需要将代码按照python包的方式组织,即包具有子模块属性,那么需要在__init__.py文件中对子模块进行导入。下面的演示包含了使用空的__init__.py文件和包含导入子模块代码的__init__.py文件。注意在notebook中演示以下两段代码之前最好重启一下服务,因为一些缓存机制会使实验效果出现混淆。

5bb81dcfbb36ec6934b0fef379e76ac0.png

空与非空__init__.py的差异

从演示结果来看,在__init__.py中包含子模块导入的操作之后,该模块的__dir__()函数中包含了子模块名,而在空的__init__.py文件演示中,模块对应的__dir__()函数就没有子模块的名字。这有什么意义呢?这个的意义在于,对于空__init__.py,如果单独导入模块是没有作用的,因为没有可供调用的子模块。也就是说,空__init__.py的目录只适合作为模块代码组织中的中间命名空间,而不是真正功能完整的python包。

3. 导入所有子模块

虽然使用星号导入所有子模块并不是很推荐的编写代码的方式,但是日常开发中这样使用确实能增加一些效率。而且在一些不是太正式的项目中也是比较常用。有两种方式可以实现,一种是在__init__.py文件中使用import语句逐个导入子模块,另一种方式是将子模块名填充到__all__变量中。

88981006376869553eb5111124e93f71.png

导入所有子模块

到此,关于python中的__init__.py文件的使用就讨论到这里。那么本文开头所描述的情形能够实现了吗?其实就是在__init__.py文件中将每个子模块中的模型都导入,就可以实现对外接口与单个文件模块一致。本文的notebook版文件将在github上的cnbluegeek/notebook仓库中共享,欢迎感兴趣的朋友前往下载。需要说明的是,如果想要复现本文实验结果,需要在每个实验之前重启一下notebook的服务核心,避免缓存引起的混淆。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值