在python中定义私有模块函数

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

313270 次浏览

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

< em >类士兵< / em >< em >模块士兵< / em >之间可能有混淆。

A 模块的私人一个下划线
开头 当使用import命令的from <module_name> import *形式时,这样的元素不会被复制;然而,如果使用import <moudule_name>语法(请看本·威廉的回答)
,则会导入 只要从问题示例的a.__num中删除一个下划线,它就不会在使用from a import *语法导入a.py的模块中显示

A 类私人两个下划线开头(又名dunder,即d-ouble underscore)
这样的变量名称为“mangled”,以包含类名等 它仍然可以在类逻辑之外通过被修改的名称访问 尽管名称破坏可以作为一种轻度的防止未经授权访问的设备,但其主要目的是防止可能与祖先类的类成员发生名称冲突。 参见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中,“隐私”取决于“成年人的同意程度”——你不能它(就像你在现实生活中一样;-)。一个前导下划线意味着你不是应该“从外部”访问它——两个前导下划线(w/o后面的下划线)传递的信息更有力……但是,最后,它仍然取决于社会习俗和共识:Python的自省足够强大,以至于你不能思想上的桎梏世界上所有其他程序员都尊重你的愿望。

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

这个问题并没有完全得到回答,因为模块隐私并不是完全常规的,而且由于使用进口可能识别也可能不识别模块隐私,这取决于它的使用方式。

如果你在一个模块中定义私有名称,这些名称将被导入到任何使用'import module_name'语法的脚本中。因此,假设您在示例中正确定义了模块private, _num,在a.py中,如下所示..

#a.py
_num=1

..你可以在b.py中使用模块名符号来访问它:

#b.py
import a
...
foo = a._num # 1

要从a.py中只导入非私有对象,必须使用语法:

#b.py
from a import *
...
foo = _num # throws NameError: name '_num' is not defined

然而,为了清晰起见,在从模块中导入名称时最好显式,而不是用'*'导入它们:

#b.py
from a import name1
from a import name2
...

Python有三种模式via。当导入一个模块时,只有public模式是可访问的。因此private和protected模块不能从模块外部调用,即当它被导入时。

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

__abc0»__abc1»__abc2

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

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

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

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

如果你真的需要那种程度的隐私的话。

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

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

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

抱歉我回答晚了,但是在一个模块中,你可以将包定义为“export”。是这样的:

mymodule
__init__.py
library.py
main.py

mymodule里/ library.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'))

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

看到PEP8指南:

方法名称和实例变量

使用函数命名规则:小写字母,单词之间用下划线分隔,必要时进行改进 可读性。< / p > 只对非公共方法和实例使用一个前导下划线 变量。< / p >

为了避免与子类名称冲突,使用两个前导下划线

Python将这些名称与类名混淆:如果类Foo有一个 属性名为__a,它不能被Foo.__a访问。(一种坚持 用户仍然可以通过调用Foo._Foo__a获得访问权限。)一般来说, 双前导下划线应仅用于避免名称冲突

为传承而设计

总是决定一个类的方法和 实例变量(统称为“attributes”)应该是public或 非公有制。如果有疑问,选择非公募;做起来更容易

.

.

公共属性是那些您期望与您的客户端无关的属性 类的使用,与您的承诺避免向后不兼容 的变化。非公共属性是那些不打算成为公共属性的属性 第三方使用的;你不能保证非公开的 属性不会改变,甚至不会被删除 这里我们不使用术语“私有”,因为没有属性是真正的

. private在Python中(通常没有不必要的工作量)