根据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错了,还是我误解了什么?是否有方法将模块的函数定义为私有?


当前回答

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

模块私有以一个下划线开始 当使用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
>>>

其他回答

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

抱歉我回答晚了,但是在一个模块中,你可以像这样定义包来“导出”:

mymodule
  __init__.py
  library.py
main.py

我的模块/库.py

# 'private' function
def _hello(name):
    return f"Hello {name}!"

# 'public' function which is supposed to be used instead of _hello
def hello():
    name = input('name: ')
    print(_hello(name))

mymodule里/ __init__ . py

# only imports certain functions from library
from .library import hello

main.py

import mymodule
mymodule.hello()

尽管如此,函数仍然可以被访问,

from mymodule.library import _hello
print(_hello('world'))

但这种方法使其不那么明显

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

模块私有以一个下划线开始 当使用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
>>>

In Python, "privacy" depends on "consenting adults'" levels of agreement - you can't force it (any more than you can in real life;-). A single leading underscore means you're not supposed to access it "from the outside" -- two leading underscores (w/o trailing underscores) carry the message even more forcefully... but, in the end, it still depends on social convention and consensus: Python's introspection is forceful enough that you can't handcuff every other programmer in the world to respect your wishes.

((顺便说一下,虽然这是一个严格保密的秘密,但对于c++来说也是如此:在大多数编译器中,在#包括你的.h文件之前,一个简单的#define private public line就可以让狡猾的编码器对你的“隐私”进行散列…!-))

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

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

other_file.py

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

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