Python中的私有成员

Python中的私有成员,python,class,oop,member-variables,Python,Class,Oop,Member Variables,如何在Python中使方法和数据成员私有?或者Python不支持私有成员 如果Python函数的名称, 类方法,或属性以 (但不是以)两个结尾 强调,这是私人的一切 其他的都是公开的。Python没有概念 受保护类方法的类型(可访问) 只有他们自己的阶级和后代 课程)。类方法是 私人(仅在其自己的 类)或公共(可从 任何地方) “私有”实例变量 只能从内部访问 一个对象,在Python中不存在。 然而,有一个惯例是 后面是大多数Python代码:名称 以下划线作为前缀(例如。 _垃圾邮件)应

如何在Python中使方法和数据成员私有?或者Python不支持私有成员

如果Python函数的名称, 类方法,或属性以 (但不是以)两个结尾 强调,这是私人的一切 其他的都是公开的。Python没有概念 受保护类方法的类型(可访问) 只有他们自己的阶级和后代 课程)。类方法是 私人(仅在其自己的 类)或公共(可从 任何地方)

“私有”实例变量 只能从内部访问 一个对象,在Python中不存在。 然而,有一个惯例是 后面是大多数Python代码:名称 以下划线作为前缀(例如。 _垃圾邮件)应被视为API的非公开部分(无论是否 是函数、方法还是数据 成员)。这应该被视为一种挑战 实施细节和可能的风险 未经通知而更改

因为有一个有效的用例 类私有成员(即避免 名称与名称的冲突 由子类定义),有 对这一机制的支持有限, 叫“弄脏”这个名字。任何标识符 垃圾邮件的形式(至少两种) 前导下划线,最多一个 尾随下划线)以文本形式显示 替换为
\u classname\u垃圾邮件
,其中 classname是当前的类名 去掉前导下划线。 这种弄脏是不加考虑的 到的句法位置 标识符,只要它出现 在类的定义中

所以

将输出:

['_Test__private_symbol', 
'__doc__', 
'__module__', 
'normal_symbol']

\uuuu private\u symbol
应视为专用方法,但仍可通过
\u Test\uu private\u symbol
访问。其他答案提供了技术细节。我想强调Python与C++/Java等语言(基于您的问题,我认为您熟悉这些语言)在哲学上的差异

Python(以及Perl)的一般态度是,属性的“隐私”是程序员的请求,而不是编译器/解释器的铁丝网。这一想法在中得到了很好的总结,通常被称为“我们都是同意的成年人”,因为它“假设”程序员有足够的责任,不干涉内部事务。前导下划线用作礼貌信息,表示该属性是内部属性


另一方面,如果您确实希望访问某些应用程序的内部构件(一个显著的例子是像pydoc这样的文档生成器),您可以自由地这样做。作为一名程序员,你有责任知道自己在做什么并正确地做,而不是用语言强迫你按自己的方式做。

Python中没有任何其他访问保护机制的
private
。中有一个约定,用于向类的用户指示他们不应访问某些属性

  • _单前导下划线:弱“内部使用”指示器。例如,M import*中的
    不会导入名称以下划线开头的对象

  • 单尾随下划线:按惯例使用,以避免与Python关键字冲突,例如
    Tkinter.Toplevel(master,class='ClassName')

  • __双下划线:在命名类属性时,调用名称混乱(在类FooBar中,\uuuboo变成了\ufoobar\uboo;见下文)


Python不直接支持隐私。程序员需要知道何时从外部修改属性是安全的,但无论如何,使用python,您可以通过一些小技巧实现类似private的功能。 现在,让我们看看一个人是否可以把任何私人的东西

class Person(object): def __priva(self): print "I am Private" def publ(self): print " I am public" def callpriva(self): self.__priva() 类人(对象): 隐私权(自我): 打印“我是私人” def publ(自我): 打印“我是公众” def callpriva(自我): 自我保护 现在我们将执行:

>>> p = Person() >>> p.publ() I am public >>> p.__priva() Traceback (most recent call last): File "", line 1, in p.__priva() AttributeError: 'Person' object has no attribute '__priva' ​#Explanation : You can see here we are not able to fetch that private method directly. >>> p.callpriva() I am Private #​Explanation : Here we can access private method inside class​ >>>p=人() >>>p.publ() 我是公众 >>>p._upriva() 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 p、 _uuupriva() AttributeError:“Person”对象没有属性“\u priva” ​#说明:您可以在这里看到,我们无法直接获取该私有方法。 >>>p.callpriva() 我是私人的 #​说明:这里我们可以访问类内部的私有方法​ ​那么人们如何访问该变量呢?
你可以这样做:

>>>p._Person__priva I am Private >>>p、 私人 我是私人的 ​哇,事实上,如果python得到任何以双下划线开头的变量,则会通过在开头添加一个下划线和类名来“转换”:

注意:如果您不希望更改此名称,但仍希望发送信号让其他对象远离,则可以使用带有初始下划线的单个初始下划线名称。不使用带星号的导入(从模块导入*)导入名称。
例如:

#test.py def hello(): print "hello" def _hello(): print "Hello private" #---------------------- #test.py def hello(): 打印“你好” def_hello(): 打印“Hello private” #---------------------- #test2.py 从测试导入* 打印hello() 打印_hello() 输出-->

你好 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 NameError:未定义名称“\u hello” 现在,如果我们手动打电话给你好

#test2.py from test import _hello , hello print hello() print _hello() #test2.py 从测试导入(hello,hello) 打印hello() 打印_hello() 输出-->

你好 你好,二等兵 最后:Python实际上没有同等的隐私支持,尽管是单一的
如果您想在Python中使方法或数据成员私有,双首下划线在某种程度上为您提供了两个级别的隐私

, 使用_usetattr__

class Number:
    def __init__(self,value):
        self.my_private = value

    def __setattr__(self, my_private, value):
        # the default behavior
        # self.__dict__[my_private] = value
        raise Exception("can't access private member-my_private")


def main():
    n = Number(2)
    print(n.my_private)

if __name__ == '__main__': 
    main()
这可能会奏效:

import sys, functools

def private(member):
    @functools.wraps(member)
    def wrapper(*function_args):
      myself = member.__name__
      caller = sys._getframe(1).f_code.co_name
      if (not caller in dir(function_args[0]) and not caller is myself):
         raise Exception("%s called by %s is private"%(myself,caller))
      return member(*function_args)
    return wrapper

class test:
   def public_method(self):
      print('public method called')

   @private
   def private_method(self):
      print('private method called')

t = test()
t.public_method()
t.private_method()

这是一个l-o-n-g的答案,但我认为它触及了真正问题的根源——可见性的范围。坚持住,让我慢慢来

简单地导入一个模块不一定会让应用程序开发人员访问所有i #test2.py from test import _hello , hello print hello() print _hello() hello hello private
class Number:
    def __init__(self,value):
        self.my_private = value

    def __setattr__(self, my_private, value):
        # the default behavior
        # self.__dict__[my_private] = value
        raise Exception("can't access private member-my_private")


def main():
    n = Number(2)
    print(n.my_private)

if __name__ == '__main__': 
    main()
import sys, functools

def private(member):
    @functools.wraps(member)
    def wrapper(*function_args):
      myself = member.__name__
      caller = sys._getframe(1).f_code.co_name
      if (not caller in dir(function_args[0]) and not caller is myself):
         raise Exception("%s called by %s is private"%(myself,caller))
      return member(*function_args)
    return wrapper

class test:
   def public_method(self):
      print('public method called')

   @private
   def private_method(self):
      print('private method called')

t = test()
t.public_method()
t.private_method()
class MyOBject(object):
    def __init__(self):
        self.__private_field = 10


my_object = MyOBject()
print(my_object.__private_field)