import *,__all____init__.py__main__.py

-- TOC --

阅读并理解代码,首先要精通语法,本文尝试理清几个Python重要的语法细节。

import *(star import)

这个词我也不记得是在什么地方看到的了,它表示这样的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 a.b

这种语句,实际上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 --