在Python中定义私有模块函数
根据 这个链接:
像大多数编程语言一样,Python也有私有元素的概念:
- 私有函数,不能从模块外部调用
但是,如果我定义了两个文件:
#a.py
__num=1
还有:
#b.py
import a
print a.__num
当我运行 b.py
时,它会输出 1
,而且没有任何异常。这是因为 diveintopython 的说法错了吗,还是我理解错了什么?有没有办法确实将一个模块的函数定义为私有的呢?
11 个回答
这个问题没有得到完全的解答,因为模块的隐私并不是完全按照约定来处理的,而且使用import时,是否能识别模块的隐私取决于具体的用法。
如果你在一个模块中定义了私有名称,这些名称会被导入到任何使用了'import module_name'语法的脚本中。因此,假设你在a.py中正确地定义了私有变量_num,如下所示:
#a.py
_num=1
..你就可以在b.py中通过模块名称来访问它:
#b.py
import a
...
foo = a._num # 1
如果你只想从a.py中导入非私有的内容,你必须使用from语法:
#b.py
from a import *
...
foo = _num # throws NameError: name '_num' is not defined
为了更清楚,最好在从模块导入名称时明确指定,而不是用'*'把所有内容都导入:
#b.py
from a import name1
from a import name2
...
在这里,大家可能会对类私有变量和模块私有变量感到困惑。
模块私有变量是以一个下划线开头的。
当你使用from <模块名> import *
这种方式导入时,这种变量不会被复制;但如果你用import <模块名>
的方式导入,它还是会被导入的(可以参考Ben Wilhelm的回答)。
简单来说,如果你把问题中提到的a.__num
的一个下划线去掉,那么在使用from a import *
导入a.py的模块中,这个变量就不会显示了。
类私有变量是以两个下划线开头的(也叫做双下划线,英文是 d-ouble under-score)。
这样的变量名字会被“变形”,也就是说它的名字会包含类名等信息。
虽然可以通过变形后的名字在类的外部访问这个变量,但这并不是推荐的做法。
虽然名字变形可以稍微防止未经授权的访问,但它的主要目的是为了避免与父类的成员变量发生名字冲突。你可以看看Alex Martelli对这个约定的幽默而准确的描述,他提到的“同意的成年人”就是在说这些变量的命名规则。
>>> class Foo(object):
... __bar = 99
... def PrintBar(self):
... print(self.__bar)
...
>>> myFoo = Foo()
>>> myFoo.__bar #direct attempt no go
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__bar'
>>> myFoo.PrintBar() # the class itself of course can access it
99
>>> dir(Foo) # yet can see it
['PrintBar', '_Foo__bar', '__class__', '__delattr__', '__dict__', '__doc__', '__
format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__
', '__subclasshook__', '__weakref__']
>>> myFoo._Foo__bar #and get to it by its mangled name ! (but I shouldn't!!!)
99
>>>
在Python中,“隐私”其实是看大家的共识和同意程度的——你不能强迫别人遵守。一个前面加一个下划线的变量,意味着你不应该“从外部”去访问它;而前面加两个下划线(没有后面的下划线)则更加强调这一点……不过,最终还是得靠大家的社会习惯和共识来决定:Python的反射功能很强大,你无法让全世界的程序员都遵循你的意愿。
(顺便说一下,虽然这是个小秘密,但C++也是类似的:在大多数编译器中,只需在包含你的头文件之前加一行 #define private public
,聪明的程序员就能轻松破解你的“隐私”……!)