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

像大多数语言一样,Python具有 私有元素的概念: 私人 函数,这些函数不能被调用 在模块外

然而,如果我定义两个文件:

#a.py
__num=1

and:

#b.py
import a
print a.__num

当我运行b.py时,它输出1而不给出任何异常。是diveintopython错了,还是我误解了什么?是否有方法将模块的函数定义为私有?


当前回答

这是一个古老的问题,但是模块私有(一个下划线)和类私有(两个下划线)被破坏的变量现在都包含在标准文档中:

Python教程»类»私有变量

其他回答

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

见PEP8指南:

方法名称和实例变量

Use the function naming rules: lowercase with words separated by underscores as necessary to improve readability. Use one leading underscore only for non-public methods and instance variables. To avoid name clashes with subclasses, use two leading underscores to invoke Python’s name mangling rules. Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a. (An insistent user could still gain access by calling Foo._Foo__a.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.

为传承而设计

Always decide whether a class’s methods and instance variables (collectively: “attributes”) should be public or non-public. If in doubt, choose non-public; it’s easier to make it public later than to make a public attribute non-public. Public attributes are those that you expect unrelated clients of your class to use, with your commitment to avoid backwards incompatible changes. Non-public attributes are those that are not intended to be used by third parties; you make no guarantees that non-public attributes won’t change or even be removed. We don’t use the term “private” here, since no attribute is really private in Python (without a generally unnecessary amount of work).

可能会混淆类私有和模块私有。

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

A class private starts with two underscores (aka dunder i.e. d-ouble under-score) Such a variable has its name "mangled" to include the classname etc. It can still be accessed outside of the class logic, through the mangled name. Although the name mangling can serve as a mild prevention device against unauthorized access, its main purpose is to prevent possible name collisions with class members of the ancestor classes. See Alex Martelli's funny but accurate reference to consenting adults as he describes the convention used in regards to these variables.

>>> 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
>>>

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

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

这是一个古老的问题,但是模块私有(一个下划线)和类私有(两个下划线)被破坏的变量现在都包含在标准文档中:

Python教程»类»私有变量