代码之家  ›  专栏  ›  技术社区  ›  appusajeev

python中的私有成员

  •  60
  • appusajeev  · 技术社区  · 15 年前

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

    8 回复  |  直到 7 年前
        1
  •  72
  •   Fish Monitor    12 年前

    9.6. Private Variables

    _156;private_157;实例变量 只能从内部访问 对象,在python中不存在。 然而,有一个惯例是 后面是大多数python代码:一个名称 前缀为下划线(例如 _ spam)应被视为API的非公共部分(无论 是函数、方法或数据 成员)。它应该被认为是 实施细节,以 更改,恕不另行通知。

    因为有一个有效的用例 班级私人成员(即避免 名称与名称冲突 由子类定义),有 对这种机制的支持有限, 名字叫曼格林。任何标识符 垃圾邮件的形式(至少两个 前导下划线,最多一个 尾随下划线)是文本形式的 换成 _classname__spam 在哪里 class name是当前类名 去掉前导下划线。 这项工作是不加考虑的。 到的句法位置 标识符,只要它出现 在类的定义中。

    所以, for example ,

    class Test:
        def __private_symbol(self):
            pass
        def normal_symbol(self):
            pass
    
    print dir(Test)
    

    意志产出:

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

    __private_symbol 应该被视为私有方法,但仍然可以通过 _Test__private_symbol .

        2
  •  32
  •   Noufal Ibrahim    15 年前

    其他答案提供了技术细节。我想强调一方面Python和C++/Java语言之间的哲学上的差异(我假定你是基于你的问题熟悉的)。

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

    另一方面,如果你 想要访问一些应用程序的内部结构(一个值得注意的例子是文档生成器,比如pydoc),您可以自由地这样做。作为一个程序员,你有责任知道你在做什么,并正确地做,而不是用语言强迫你去做事情。 它是 方式。

        3
  •  6
  •   Tendayi Mawushe    15 年前

    没有 private 在python中的任何其他访问保护机制。有一个公约记录在 Python style guide 用于向类的用户指示他们不应访问某些属性。

    • _单一领先者下划线:弱的“内部使用”指标。例如。 from M import * 不导入名称以下划线开头的对象。

    • single_trailing_underline_u:由约定使用,以避免与python关键字冲突,例如 Tkinter.Toplevel(master, class_='ClassName')

    • _双前导下划线:当命名一个类属性时,调用名称管理(在类foobar内,uboo变为foobar_uboo;见下文)。

        4
  •  6
  •   Bill the Lizard    12 年前

    如果python函数的名称, 类方法或属性以开头 (但不以)二 下划线,它是私有的; 一切 其他是公开的。python没有概念 保护类方法(可访问 只有在他们自己的阶级和后代中 类)。类方法可以是 私人(仅在他们自己的地方可访问 类)或公共(可从 任何地方)。

    Dive Into Python

        5
  •  5
  •   Prashant Gaur    11 年前

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

    class Person(object):
    
        def __priva(self):
            print "I am Private"
    
        def publ(self):
            print " I am public"
    
        def callpriva(self):
            self.__priva()
    

    现在,当我们执行:

    >>> 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​
    

    _139;那么有人如何访问这个变量????
    你可以这样做:

    >>>p._Person__priva
    I am Private
    

    _139;wow,实际上,如果python获得任何以双下划线开头的变量,则通过在开头添加一个下划线和类名进行翻译:

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

    #test.py
    def hello():
        print "hello"
    def _hello():
        print "Hello private"
    
    #----------------------
    
    #test2.py
    from test import *
    print hello()
    print _hello()
    

    输出-gt;

    hello
    Traceback (most recent call last):
      File "", line 1, in 
    NameError: name '_hello' is not defined
    

    现在,如果我们手动打电话给你好。

    #test2.py
    from test import _hello , hello
    print hello()
    print _hello()
    

    输出-gt;

    hello
    hello private
    

    最后:python并不真正具有同等的隐私支持,尽管它是单一的 双首下划线在某种程度上为您提供了两个级别的隐私

        6
  •  2
  •   Laszlo    8 年前

    这可能有效:

    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()
    
        7
  •  1
  •   We_Are_Borg    8 年前

    这有点像是L-O-N-G的答案,但我认为它找到了真正问题的根源——可见性范围。在我艰难地完成这件事的时候,坚持住!

    简单地导入一个模块不一定能让应用程序开发人员访问它的所有类或方法;如果我不能真正看到模块源代码,我怎么知道什么是可用的?有人(或某些事情)必须告诉我我能做什么,并解释如何使用那些允许我使用的功能,否则整个事情对我来说都是无用的。

    那些通过导入的模块开发基于基本类和方法的高级抽象的人会得到一个规范文档,而不是实际的源代码。

    模块规范描述了客户机开发人员可以看到的所有特性。在处理大型项目和软件项目团队时,模块的实际实现应该始终对使用它的人保持隐藏——它是一个带有外部世界接口的黑盒。对于纯粹主义者来说,我认为技术术语是“脱钩”和“连贯”。模块用户只需要知道接口方法,而不需要对实现细节进行负担。

    如果不首先更改模块的基础规范文档,则不应更改模块,因为在更改代码之前,可能需要在某些组织中进行审查/批准。

    作为业余程序员(现已退休),我开始了一个新的模块,在模块顶部实际写出了一个巨大的注释块spec doc,这将是用户在spec库中实际看到的部分。因为只有我一个人,我还没有建立一个图书馆,但这很容易做到。

    然后,我通过编写各种类和方法开始编码,但没有函数体——只有“print()”之类的空print语句——这足以让模块编译时不出现语法错误。完成此步骤后,我将编译完成的空模块——这是我的规范。如果我在项目团队中工作,我将在充实主体之前呈现此规范/接口以供审阅和评论。

    我一次充实每个方法的主体,并相应地编译,确保立即修复语法错误。这也是开始在底部编写一个临时的“主”执行部分以在编写代码时测试每个方法的好时机。当编码/测试完成时,所有测试代码都会被注释掉,直到您再次需要它时才需要更新。

    在实际的开发团队中,spec注释块也会出现在文档控制库中,但这是另一个故事。要点是:作为模块客户机,您只能看到这个规范,而不能看到源代码。

    PS:很久以前,我在国防航空航天界工作,我们做了一些很酷的工作,但是像专有算法和敏感系统控制逻辑之类的东西在超级duper安全软件库中被严密地存储和加密。我们可以访问模块/包接口,但不能访问blackbox实现体。有一个文档管理工具可以处理所有系统级的设计、软件规范、源代码和测试记录——所有这些都是同步的。政府对软件质量保证标准有严格要求。有人记得一种叫“Ada”的语言吗?我多大了!

        8
  •  -1
  •   liorb87    9 年前

    如果要使方法或数据成员在Python中成为私有的, 使用\u setattr__

    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()