293

根据http://www.faqs.org/docs/diveintopython/fileinfo_private.html

像大多数语言一样,Python 有私有元素的概念:

  • 私有函数,不能 从其模块外部调用

但是,如果我定义两个文件:

#a.py
__num=1

和:

#b.py
import a
print a.__num

当我运行b.py它时,它会打印出来,1没有任何异常。是diveintopython错了,还是我误解了什么?有没有办法将模块的功能定义为私有的?

4

9 回答 9

409

在 Python 中,“隐私”取决于“同意成年人”的协议水平——你不能强迫它(就像你在现实生活中一样;-)。一个前导下划线意味着您不应该“从外部”访问它 -两个前导下划线(没有尾随下划线)更加有力地传达信息......但最终,它仍然取决于社交约定和共识:Python 的自省功能足够强大,以至于你不能给世界上所有其他程序员戴上手铐来尊重你的意愿。

((顺便说一句,虽然这是一个保密的秘密,但对于 C++ 来说也是如此:对于大多数编译器,在ing 你的文件#define private public之前只需一行简单的代码就可以让狡猾的编码人员对你的“隐私”进行散列......!-) )#include.h

于 2009-10-10T05:43:03.570 回答
333

类 privates模块 privates之间可能存在混淆。

一个私有的模块一个下划线开头
这样一个元素在使用from <module_name> import *import 命令的形式时不会被复制;但是,如果使用import <moudule_name>语法(请参阅 Ben Wilhelm 的回答) ,它会被导入
,只需从问题示例的 a.__num 中删除一个下划线,它就不会显示在使用from a import *语法导入 a.py 的模块中。

私有类以两个下划线开头 (又名 dunder 即 d-ouble 下划线)
这样的变量的名称“错位”以包含类名等。
它仍然可以通过错位名称在类逻辑之外访问。
尽管名称修改可以作为一种温和的预防装置来防止未经授权的访问,但其主要目的是防止与祖先类的类成员可能发生的名称冲突。请参阅 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
>>>
于 2009-10-10T05:40:54.340 回答
95

这个问题没有完全回答,因为模块隐私不是纯粹的传统,而且使用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
...
于 2012-11-29T03:50:32.373 回答
35

Python 允许使用双下划线前缀的私有类成员。这种技术在模块级别不起作用,所以我认为这是 Dive Into Python 中的一个错误。

这是私有类函数的示例:

class foo():
    def bar(self): pass
    def __bar(self): pass

f = foo()
f.bar()   # this call succeeds
f.__bar() # this call fails
于 2009-10-10T05:39:17.650 回答
30

您可以添加一个内部函数:

def public(self, args):
   def private(self.root, data):
       if (self.root != None):
          pass #do something with data

如果您真的需要那种级别的隐私,那么类似的东西。

于 2018-03-30T12:43:43.160 回答
4

这是一个古老的问题,但标准文档中现在涵盖了模块私有(一个下划线)和类私有(两个下划线)错位变量:

Python 教程»»私有变量

于 2017-09-14T09:26:39.207 回答
1

嵌入闭包或函数是一种方法。这在 JS 中很常见,但对于非浏览器平台或浏览器工作者来说不是必需的。

在 Python 中,这似乎有点奇怪,但如果确实需要隐藏某些东西,那可能就是这样。更重要的是,使用 python API 并将需要隐藏在 C(或其他语言)中的东西可能是最好的方法。如果失败了,我会把代码放在一个函数中,调用它并让它返回你想要导出的项目。

于 2018-01-14T11:25:00.843 回答
0

对于方法:(我不确定这是否正是您想要的)

print_三次.py

def private(method):
    def methodist(string):
        if __name__ == "__main__":
            method(string)
    return methodist
    
@private
def private_print3(string):
    print(string * 3)

private_print3("Hello ") # output: Hello Hello Hello

其他文件.py

from print_thrice import private_print3
private_print3("Hello From Another File? ") # no output

这可能不是一个完美的解决方案,因为您仍然可以“看到”和/或“调用”该方法。无论如何,它不会执行。

于 2020-07-23T07:38:51.420 回答
-21

Python具有三种模式,私有,公共和受保护。在导入模块时,只能访问公共模式。因此不能从模块外部调用私有和受保护模块,即在导入时。

于 2016-06-18T08:40:48.907 回答