Part.I 预备知识
Chap.I 几个概念的区分
- Python 模块(
Module ),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和 Python 语句。 - Python 包是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包等组成的 Python 的应用环境。简单来说,包就是文件夹,但该文件夹下必须存在
__init__.py 文件, 该文件的内容可以为空。__init__.py 用于标识当前文件夹是一个包。 - 文件夹:文件夹就是不存在
__init__.py 文件的文件夹。
Chap.II 模块中的 all 变量
__all__ 是针对模块公开接口的一种约定,以提供了“白名单”的形式暴露接口。如果定义了__all__ ,其他文件中使用from xxx import * 导入该文件时,只会导入 __all__ 列出的成员,可以其他成员都被排除在外。
定义 all 需要注意的地方
__all__ 的形式都是 list类型。如果写成其他类型, pyflakes 等 lint 工具可能无法识别。- 不能动态生成
__all__ ,如使用列表解析式。__all__ 的作用是定义公开接口,需要以字面量的形式显式写出来。 - 即使定义了
__all__ , 也不应该在非临时代码中使用 from xxx import * 语法,或用编程工具模拟 Ruby 的自动 import 。Python 不像 Ruby ,没有 Module 这类成员,模块就是命名空间隔离的执行者。如果打破了这一层,引入诸多动态因素,生产环境中跑的代码就可能充满不确定性,调试也会变得困难。 - 按照
PEP8 建议的风格,__all__ 应该写在所有 import 语句下面,函数、常量等成员定义的上面。 - 如果一个模块需要暴露的接口改动频繁,
__all__ 可以这样定义,这样修改一个暴露的接口只修改一行,方便版本控制的时候看 diff。最后多出的逗号在 Python 中是允许的,符合 PEP8 风格。
__all__ = [
"foo",
"bar",
"egg",
]
Part.II 导入模块的几种方法
Chap.I 方法
Python 导入模块一般用到两种方法:
import model1 from model import xxx
当我们向文件导入某个模块时,导入的是该模块中那些名称不以下划线(单下划线_ 或者双下划线__ )开头的变量、函数和类。因此,如果我们不想模块文件中的某个成员被引入到其它文件中使用,可以在其名称前添加下划线。
除此之外,还可以借助模块提供的 __all__ 变量,该变量的值是一个列表,存储的是当前模块中一些成员(变量、函数或者类)的名称。通过在模块文件中设置 __all__ 变量,当其它文件以from 模块名 import * 的形式导入该模块时,该文件中只能使用 __all__ 列表中指定的成员。
也就是说,当使用from 模块名 import * 方法导入模块的时候,不会导入下划线_ 函数;另外,如果模块中有__all__ ,则导入的函数还要受到__all__ 的控制;当使用import 模块名 导入函数时,则不会受到上面两个的限制。
所以,以后在确定某些函数不想被访问到,就用下划线_ 或者用__all__ ,并使用from 模块名 import * 方法导入模块;当想要使用模块中的所有函数时,则使用import 模块名 来导入模块。
Chap.II 实例
比如现在有个文件叫b.py
__all__ = [
'b_hello',
'_b_hello'
]
def b_hello():
print("B_HELLO")
def _b_hello():
print("B_private")
def b_world():
print("B_private_world")
现在使用from 模块名 import * 方法导入模块来调用函数:
from b import *
b_hello()
_b_hello()
b_world()
B_HELLO
Error:xxxxx
B_private_world
B_HELLO
B_private
Error:xxxxx
使用__all__ 变量,使得原本不能被访问到的_b_hello 可以被访问到;因为__all__ 中没有包含b_world ,所以使得原本能被访问到的b_world 不能被访问到。
现在使用import 模块名 方法导入模块来调用函数:
import b
b.b_hello()
b._b_hello()
b.b_world()
B_HELLO
B_private
B_private_world
所以,以后在确定某些函数不想被访问到,就用下划线_ 或者用__all__ ,并使用from 模块名 import * 方法导入模块;当想要使用模块中的所有函数时,则使用import 模块名 来导入模块。
ps:当包(含有__init__.py 文件的文件夹)中含有子模块时,可以使用. 来导入。比如import lib.model1 as md ,就是调用包lib 中的模块model1 。
|