美文网首页
单下划线和双下划线的区别

单下划线和双下划线的区别

作者: 胖虎很可爱 | 来源:发表于2018-04-20 16:09 被阅读0次

    主要存在四种命名

    1. object # 公用方法
    2. __object__ # 内建方法,用户不要这样定义
    3. __object # 全私有,全保护
    4. _object # 半保护
    

    核心风格:避免用下划线作为变量名的开始。

    因为下划线对解释器有特殊的意义,而且是内建标识符所使用的符号,我们建议程序员避免用下划线作为变量名的开始。一般来讲,变量名_object被看作是“私有的”,在模块或类外不可以使用,不能用’from module import *’导入。当变量是私有的时候,用_object来表示变量是很好的习惯。

    单下划线+类名,eg:_Class__object 机制就可以访问__object__了。因为变量名__object__对Python 来说有特殊含义,对于普通的变量应当避免这种命名风格。

    “单下划线” 开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量;”双下划线” 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。(如下列所示)

    以单下划线开头_foo的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用“from xxx import *”而导入;以双下划线开头的__foo代表类的私有成员;以双下划线开头和结尾的__foo__代表python里特殊方法专用的标识,如 __init__()代表类的构造函数。

    class Foo():
        def __init__():
            ...
    
        def public_method():
            print 'This is public method'
    
        def __fullprivate_method():
            print 'This is fullprivate_method'
    
        def _halfprivate_method():
            print 'This is halfprivate_method'
    
        f = Foo()
        f.public_method() # OK
        f.__fullprivate_method() # Error occur
        f._halfprivate_method() # OK
        f._Foo__fullprivate_method() # OK
    

    从上面的例子可以看出,f._halfprivate_method()可以直接访问,确实是。不过根据python的约定,应该将其视作private,而不要在外部使用它们,(如果你非要使用也没辙),良好的编程习惯是不要在外部使用它。同时,根据Pythondocs的说明,_object和__object的作用域限制在本模块内。

    大家看下面这段程序的输出:

    class A(object):
        def __init__(self):
            self.__private()
            self.public()
        def __private(self):
            print 'A.__private()'
        def public(self):
            print 'A.public()'
    class B(A):
        def __private(self):
            print 'B.__private()'
        def public(self):
            print 'B.public()'
    b = B()
    

    初探
    正确的答案是:
    A.__private()
    B.public()

    我们分别看下类A和类B的属性都有哪些:

    >>> print '\n'.join(dir(A))
    _A__private
    __init__
    public
    
    >>> print '\n'.join(dir(B))
    _A__private
    _B__private
    __init__
    public
    

    为什么类A有个名为_A__private的 属性呢?而且__private消失了!这就要谈谈Python的私有变量“矫直”了。

    Python把以两个或以上下划线字符开头且没有以两个或以上下划线结尾的变量当作私有变量。私有变量会在代码生成之前被转换为长格式(变为公有)。转换机制是这样的:在变量前端插入类名,再在前端加入一个下划线字符。这就是所谓的私有变量矫直(Private name mangling)。如类 A里的__private标识符将被转换为_A__private,这就是上一节出现_A__private__private消失的原因了。

    再讲两点题外话:

    一是因为矫直会使标识符变长,当超过255的时候,Python会切断,要注意因此引起的命名冲突。

    二是当类名全部以下划线命名的时候,Python就不再执行矫直。如:

    class ____(object):
        def __init__(self):
            self.__method()
        def __method(self):
            print '____.__method()'
    
    print '\n'.join(dir(____))
    __class__
    __delattr__
    __dict__
    __doc__
    __getattribute__
    __hash__
    __init__
    __method              # 没被矫直
    __module__
    __new__
    __reduce__
    __reduce_ex__
    __repr__
    __setattr__
    __str__
    __weakref__
    
    obj = ____()
    ____.__method()
    
    obj.__method()      # 可以外部调用
    ____.__method()
    

    现在我们回过头来看看为什么会输出“A.__private()”吧!

    矫直之后,类A的代码就变成这样了:

    class A(object):
        def __init__(self):
            self._A__private()          # 这行变了
            self.public()
        def _A__private(self):           # 这行也变了
            print 'A.__private()'
        def public(self):
            print 'A.public()'
    

    因为在类B定义的时候没有覆盖__init__方法,所以调用的仍然是A.__init__,即执行了self._A__private(),自然输出“A.__private()”了。

    下面的两段代码可以增加说服力,增进理解:

    class C(A):
        def __init__(self): # 重写 __init__ ,不再调用self._A__private
            self.__private()# 这里绑定的是 _C_private
            self.public()
        def __private(self):
            print 'C.__private()'
        def public(self):
            print 'C.public()'
    
    c = C()
    答案:
    C.__private()
    C.public()
    
    class A(object):
        def __init__(self):
            self._A__private()   # 调用一个没有定义的函数,但可执行 
            self.public()
        def __private(self):
            print 'A.__private()'
        def public(self):
            print 'A.public()'
    
    a = A()
    答案:
    A.__private()
    A.public()
    

    相关文章

      网友评论

          本文标题:单下划线和双下划线的区别

          本文链接:https://www.haomeiwen.com/subject/ziczkftx.html