在python中定义私有模块函数

ola*_*ndo 225 python module private function

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

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

  • 私有函数,无法从模块外部调用

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

#a.py
__num=1
Run Code Online (Sandbox Code Playgroud)

和:

#b.py
import a
print a.__num
Run Code Online (Sandbox Code Playgroud)

当我运行b.py它打印出来,1没有任何例外.diveintopython错了,还是我误解了什么?而且是有一些方法可以定义模块的功能为私有?

Ale*_*lli 299

在Python中,"隐私"取决于"同意成年人"的协议级别 - 你不能强迫它(在现实生活中超过你的能力;-).单个前导下划线意味着您不应该 "从外部"访问它 - 两个主要下划线(没有尾随下划线)更有力地传达信息......但是,最后,它仍然取决于社交惯例和共识:Python的内省足够强大,你不能给世界上其他程序员戴上手铐来尊重你的意愿.

((顺便说一下,虽然这是一个密切关注的秘密,但C++也是如此:对于大多数编译器来说,#define private public#include你的.h文件之前只需要一个简单的行就可以让狡猾的程序员为你的"隐私"做好准备......! - ) )

  • 你对C++的说明不正确.通过使用#define private public,您将更改发送到编译器的代码,这是名称重整的位置. (75认同)
  • 作为@rhinoinrepose的更新,它不仅是不正确的,它是[根据标准的未定义行为](/sf/ask/637656421/)使用预处理器宏重新定义关键字. (44认同)
  • C++修改也很模糊,但几乎不是秘密.您也可以"内省"C++生成的二进制文件.对不起. (12认同)
  • @AlexMartelli不是`static void foo()`是私有的.它至少对链接器是隐藏的,并且可以通过内联完全删除该函数. (3认同)
  • 您可以使用闭包将变量设为私有,然后返回要导出的变量. (2认同)
  • 在现实生活中,如果人们违反法律,就会受到起诉 (2认同)

mjv*_*mjv 269

阶级私有模块私有之间可能存在混淆.

模块私人与启动一个强调
这样的元件不使用时沿复制from <module_name> 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
>>>
Run Code Online (Sandbox Code Playgroud)

  • 根据http://stackoverflow.com/a/13618522/3155195,单个下划线的解释是错误的. (4认同)
  • @mjv 这是一个很有帮助的解释!谢谢!一段时间以来,我一直对这种行为感到非常困惑。如果您尝试直接访问私有类,我确实希望选择抛出 AttributeError 以外的某种错误;也许“PrivateAccessError”或其他更明确/有用的东西。(因为得到它没有属性的错误不是*真的*真)。 (3认同)
  • [PEP 8 -- Python 代码风格指南](https://www.python.org/dev/peps/pep-0008/#descriptive-naming-styles) `_single_leading_underscore:弱“内部使用”指示符。例如 from M import * 不会导入名称以下划线开头的对象。` (3认同)
  • @zehnpaard感谢您指出这一点!我修改了答案,以解决此错误。 (2认同)

Ben*_*elm 78

这个问题没有得到完全回答,因为模块隐私不仅仅是传统的,因为使用导入可能会或可能不会识别模块隐私,具体取决于它的使用方式.

如果在模块中定义专用名称,则会将这些名称导入到使用语法"import module_name"的任何脚本中.因此,假设您在示例中正确定义了模块private,_num,在a.py中,就像这样..

#a.py
_num=1
Run Code Online (Sandbox Code Playgroud)

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

#b.py
import a
...
foo = a._num # 1
Run Code Online (Sandbox Code Playgroud)

要仅从a.py导入非私有,必须使用from语法:

#b.py
from a import *
...
foo = _num # throws NameError: name '_num' is not defined
Run Code Online (Sandbox Code Playgroud)

但是,为了清楚起见,最好在从模块导入名称时明确,而不是使用'*'导入所有名称:

#b.py
from a import name1 
from a import name2
...
Run Code Online (Sandbox Code Playgroud)

  • @FistOfFury 是的,您指定在 `__init__.py` 文件中导入的函数。请参阅[此处](/sf/answers/4489131/)以获得一些帮助。 (2认同)

And*_*are 29

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
Run Code Online (Sandbox Code Playgroud)

  • 我认为OP的目的是编写在例如商业软件包之外无法访问的函数.在这方面,这个答案并不完整.__bar()函数仍然可以通过f._foo__bar()从外部访问.因此,双引导下划线不会将其设为私有. (2认同)

Ili*_*nov 17

您可以添加内部函数:

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

如果你真的需要这种程度的隐私,那就是这样的.

  • 为什么这不是最佳答案? (8认同)
  • 我想这是因为嵌套函数在模块中的其他任何地方都不可重用,因此定义函数没有任何好处,除非要在外部函数内多次使用它。在这种情况下,我觉得内联代码会更具可读性。 (5认同)

use*_*062 7

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

\n\n

Python 教程\xc2\xbb\xc2\xbb私有变量

\n