第10.4节 Python模块的弱封装机制
一、 引言 Python模块可以为调用者提供模块内成员的访问和调用,但某些情况下, 因为某些成员可能有特殊访问规则等原因,并不适合将模块内所有成员都提供给调用者访问,此时模块可以类似类的封装机制类似的模式提供一定的内部成员保护。 模块内的内部成员封装机制有两种,一种是定义类似类的私有成员,二是类似类的__slots__实例属性白名单机制,下面分别介绍这两种方法。
二、 定义模块的私有成员 在模块内,一个以下划线开头的成员属于模块的私有成员,在使用“from 模块名 import *”不会被导入,这和类的私有成员管理比较像,但还是有如下区别: 1、 下划线开头的成员包括了单下划线开头、双下划线开头、双下划线开头双下划线结尾的成员,它们的处理是一样的,而类中它们是不一样的,具体大家可参考; 2、 模块的私有成员使用“from 模块名 import *”这样的语句来导入模块时,程序会跳过下划线开头的模块成员,即下划线开头的所有成员都不能“from 模块名 import *”导入,但可以通过“import 模块名”或“from 模块名 import 成员”方式导入。 Python通过这种简单的名字规则来隐藏成员的方法就是模块的封装机制,可以看到其实这种封装机制很脆弱。 3、 案例: 我们定义一个imptest.py,文件内容如下:
#imptest.py def f(): print("execute ftest function in imptest....") def _f1(): print("execute _f1(单下划线开头) function in imptest....") def __f2(): print("execute __f2(双下划线开头) function in imptest....") def __f3__(): print("execute __f3__(双下划线开头结尾) function in imptest....") print("Now in imptest module!")
1)使用“from 模块名 import *”导入并调用成员执行验证是否导入成功:
>>> from imptest import * Now in imptest module! >>> f() execute ftest function in imptest.... >>> _f1() Traceback (most recent call last): File "<pyshell#2>", line 1, in <module> _f1() NameError: name _f1 is not defined >>> __f2() Traceback (most recent call last): File "<pyshell#3>", line 1, in <module> __f2() NameError: name __f2 is not defined >>> __f3__() Traceback (most recent call last): File "<pyshell#4>", line 1, in <module> __f3__() NameError: name __f3__ is not defined >>>
可以看到凡是带下划线的都没有导入。 2) 使用“import 模块名”导入并调用成员执行验证是否导入成功:
>>> import imptest Now in imptest module! >>> imptest.f() execute ftest function in imptest.... >>> imptest._f1() execute _f1(单下划线开头) function in imptest.... >>> imptest.__f2() execute __f2(双下划线开头) function in imptest.... >>> imptest.__f3__() execute __f3__(双下划线开头结尾) function in imptest.... >>>
可以看到都能正常导入使用。 本节介绍了模块中使用下划线开头定义成员能防止“from 模块名 import *”导入这些成员,这是一种Python提供的弱封装机制,但建议大家在使用时还是遵循这种机制。