__all__
,__init__.py
和__main__.py
-- TOC --
阅读并理解代码,首先要精通语法,本文尝试理清几个Python重要的语法细节。
这个词我也不记得是在什么地方看到的了,它表示这样的import语句:
from <module|package> import *
一般我们是不推荐用这样的方式做import,就像一般我们不推荐在C语言中使用goto一样!
这种star import的方式将导入模块中所有的非下划线(_
)开始的对象,这种全部导入的方式,有人说容易污染namespace,不过,还是有方法可以控制可导入对象的。
直接import,可以通过module或者package name访问所有全局对象;而star import,只会将所有非_
开始的全局对象导入当前namespace,除非定义了__all__
这个name list。
用star import存在一个问题:再用flake8做lint的时候,undefined name就无法检查了,而这个undefined name对于像python这样解释执行的语言来说,是个很重要的潜在风险点。因为undefined name只有在执行到那一行代码的时候,才知道是否正确,测试就要求100%分支覆盖,这在很多时候是比较困难和耗时的。
__all__
常常在模块中见到__all__ = [...]
。
在模块中定义此对象的作用,就是为了配合star import。
当有定义__all__
的时候,star import只会导入在__all__
中有定义的name!如果__all__
中指定的对象没有被定义,star import的时候,会抛出AttributeError。直接import时,无视__all__
。
一个值得注意的细节:import只能跟module或package,而from ... import可以跟函数,类,变量等对象!
__all__
中都是str对象。
__init__.py
当import一个package的时候,package目录中的__init__.py
文件会被执行,因此它很适合用来做package的初始化工作。
import不管是单文件的module,还是一个目录的package,都是执行一个py文件!只是
__name__
,分别是module name或者package name!
当一个目录下没有此文件时,import这个目录也能成功,但是没有任何效果,这个目录不是一个package,只是个有一堆py文件的目录,可以通过import a.b
这种方式来import其中的module。
这种语句,实际上import的是一个module c(如果c是一个py文件的话),只是这个module c的路径,是a/b
。很多时候,a可能是个package,这种就是只import某个package中的module。
一个值得注意的细节,用这种方式import,c模块在运行时的__name__ == a.b
我测试了import a.b.c,没有成功!
__main__.py
当执行一个package的时候,python解释器会去寻找__main__.py
这个模块:
$ mkdir emptyfold
$ python3 emptyfold
/usr/bin/python3: can't find '__main__' module in '/home/xinlin/test/emptyfold'
$ python3 -m emptyfold
/usr/bin/python3: No module named emptyfold.__main__; 'emptyfold' is a package and cannot be directly executed
当直接执行package的时候,python解释器回去寻找__main__.py
,从这里开始执行。当已模块的方式执行的时候,即解释器带上了-m
参数,这时先执行__init__.py
,在执行__main__.py
。
本文链接:https://cs.pynote.net/sf/python/202203223/
-- EOF --
-- MORE --