在python中定义私有模块函数
- 2025-03-18 08:55:00
- admin 原创
- 40
问题描述:
根据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 错了吗,还是我误解了什么? 有没有办法将模块的函数定义为私有的?
解决方案 1:
在 Python 中,“隐私”取决于“成年人的同意程度”——你不能强迫它。单个前导下划线意味着你不应该“从外部”访问它——两个前导下划线(没有尾随下划线)传达的信息更有力……但最终,它仍然取决于社会习俗和共识:Python 的自省足够有力,你无法束缚世界上其他每个程序员来尊重你的意愿。
((顺便说一句,虽然这是一个严格保密的秘密,但对于 C++ 来说也是如此:对于大多数编译器来说,在编译你的文件#define private public
之前只需一行简单的代码,狡猾的程序员就可以对你的“隐私”进行哈希处理...!-))#include
`.h`
解决方案 2:
类私有属性和模块私有属性之间可能会产生混淆。
私有模块以一个下划线开头,当使用import 命令的形式
时,这样的元素不会被复制;但是,如果使用语法,则会导入它(参见 Ben Wilhelm 的答案)from <module_name> import *
`import <module_name>`
a.__num
只需从问题示例中删除一个下划线,它就不会显示在使用from a import *
语法导入 a.py 的模块中。
私有类以两个下划线开头 (又名 dunder,即双下划线)
这样的变量的名称被“破坏”,包含类名等。
它仍然可以通过混乱的名称在类逻辑之外进行访问。
尽管名称修改可以作为一种温和的预防未经授权访问的手段,但其主要目的是防止与祖先类的类成员发生名称冲突。请参阅 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
>>>
解决方案 3:
这个问题没有得到完全的回答,因为模块隐私不是纯粹传统的,并且使用导入可能会或可能不会识别模块隐私,这取决于如何使用它。
如果您在模块中定义私有名称,则这些名称将被导入到使用语法“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
...
解决方案 4:
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
解决方案 5:
您可以添加内部函数:
def public(self, args):
def private(self.root, data):
if (self.root != None):
pass #do something with data
如果您确实需要这种级别的隐私,那就类似这样。
解决方案 6:
这是一个古老的问题,但现在标准文档中涵盖了模块私有(一个下划线)和类私有(两个下划线)的混乱变量:
Python 教程»类»私有变量
解决方案 7:
抱歉我回答晚了,但是在模块中,您可以像这样定义要“导出”的包:
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))
我的模块/__init__.py
# only imports certain functions from library
from .library import hello
主程序
import mymodule
mymodule.hello()
尽管如此,仍然可以访问功能,
from mymodule.library import _hello
print(_hello('world'))
但这种方法让它不那么明显
解决方案 8:
嵌入闭包或函数是一种方法。这在 JS 中很常见,但对于非浏览器平台或浏览器工作者来说不是必需的。
在 Python 中这似乎有点奇怪,但如果确实需要隐藏某些东西,那么这可能是一种方法。更重要的是,使用 Python API 并将需要隐藏的东西保留在 C(或其他语言)中可能是最好的方法。如果做不到这一点,我会将代码放在函数中,调用该函数并让它返回您想要导出的项目。
解决方案 9:
参见PEP8 指南:
方法名称和实例变量
使用函数命名规则:小写并用下划线分隔单词,以提高可读性。
仅对非公共方法和实例变量使用一个前导下划线。
为了避免与子类发生名称冲突,请使用两个前导下划线来调用 Python 的名称修改规则。
Python 将这些名称与类名混杂在一起:如果类 Foo 有一个名为 __a 的属性,则它不能被 Foo.__a 访问。(坚持的用户仍然可以通过调用 Foo._Foo__a 获得访问权限。)通常,双前导下划线仅应用于避免与设计为子类的类中的属性发生名称冲突。
为继承而设计
始终确定类的方法和实例变量(统称为“属性”)应为公共还是非公共。如果有疑问,请选择非公共;稍后将其设为公共比将公共属性设为非公共更容易。
公共属性是您希望与类无关的客户端使用的属性,并且您承诺避免向后不兼容的更改。非公共属性是不打算由第三方使用的属性;您无法保证非公共属性不会更改甚至被删除。
我们在这里不使用术语“私有”,因为在 Python 中没有属性是真正私有的(通常不需要不必要的工作)。
解决方案 10:
对于方法:(我不确定这是否正是你想要的)
打印三次.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
这可能不是一个完美的解决方案,因为您仍然可以“查看”和/或“调用”该方法。无论如何,它都不会执行。
解决方案 11:
Python 有三种模式,即私有、公共和受保护。导入模块时,只有公共模式可访问。因此,私有和受保护的模块不能从模块外部调用,即在导入时。
扫码咨询,免费领取项目管理大礼包!