zoukankan      html  css  js  c++  java
  • python——双下划线与python命名机制

    python中双下划线的作用
    (1)所有以双下划线开头的成员是私有的
    (2)python对于私有变量是会进行扎压(mangling)的,扎压规则是
    原始定义:
    class A():
        __function():
              print '__function is private! '
    扎压之后:
    class A():
        _A__function():
              print '__function is private!'

    同时,在class A中对于以前__function()的调用会被自动替换成对于_A__function()的调用。


    /**如果对于上述规则不理解,请查看下面的内容(转载过来的)**/


    引子
    我热情地邀请大家猜测下面这段程序的输出:
    class A(object):
           def __init__(self):
                  self.__private()     #如果该行代码改成self._private()
                  self.public()   
           def __private(self):  #def _private(self):
                  print 'A.__private()' #print 'A._private()'
           def public(self):
                  print 'A.public()'
    class B(A):
           def __private(self):  #def _private(self):————————b=B()的正确答案是:B._private()
                  print 'B.__private()' #print 'B._private()'                 B.public()
           def public(self):
                  print 'B.public()
    b = B()
    初探
    正确的答案是:
    A.__private()                    #因为调用A的构造函数时,加双下划线的是私有变量只有类对象自己能访问,连子类对象也不能访问到这个数据.
    B.public()                         #调用A的构造函数时,子类B的public方法覆盖父类A的Public方法。
     
    如果您已经猜对了,那么可以不看我这篇博文了。如果你没有猜对或者心里有所疑问,那我的这篇博文正是为您所准备的。
    一切由为什么会输出“A.__private()”开始。但要讲清楚为什么,我们就有必要了解一下Python的命名机制。
    据 Python manual,变量名(标识符)是Python的一种原子元素。当变量名被绑定到一个对象的时候,变量名就指代这个对象,就像人类社会一样,不是吗?当变量名出现在代码块中,那它就是本地变量;当变量名出现在模块中,它就是全局变量。模块相信大家都有很好的理解,但代码块可能让人费解些。在这里解释一下:
    代码块就是可作为可执行单元的一段Python程序文本;模块、函数体和类定义都是代码块。不仅如此,每一个交互脚本命令也是一个代码块;一个脚本文件也是一个代码块;一个命令行脚本也是一个代码块。
    接下来谈谈变量的可见性,我们引入一个范围的概念。范围就是变量名在代码块的可见性。 如果一个代码块里定义本地变量,那范围就包括这个代码块。如果变量定义在一个功能代码块里,那范围就扩展到这个功能块里的任一代码块,除非其中定义了同名 的另一变量。但定义在类中的变量的范围被限定在类代码块,而不会扩展到方法代码块中。
    迷踪
    据上节的理论,我们可以把代码分为三个代码块:类A的定义、类B的定义和变量b的定义。根据类定义,我们知道代码给类A定义了三个成员变量(Python的函数也是对象,所以成员方法称为成员变量也行得通。);类B定义了两个成员变量。这可以通过以下代码验证:
    >>> print ' '.join(dir(A))
    _A__private
    __init__
    public
    >>> print ' '.join(dir(B))
    _A__private
    _B__private
    __init__
    public
    咦,为什么类A有个名为_A__private的 Attribute 呢?而且__private消失了!这就要谈谈Python的私有变量轧压了。
    探究
    懂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 ' '.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()”吧!
    真相
    相信现在聪明的读者已经猜到答案了吧?如果你还没有想到,我给你个提示:真相跟C语言里的宏预处理差不多。
    因为类A定义了一个私有成员函数(变量),所以在代码生成之前先执行私有变量轧压(注意到上一节标红的那行字没有?)。轧压之后,类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()'
    是不是有点像C语言里的宏展开啊?
    因为在类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()   # 调用一个没有定义的函数, Python会把它给我的 
                  self.public()
           def __private(self):
                  print 'A.__private()'
           def public(self):
                  print 'A.public()'
    >>>a = A()
    A.__private()
    A.public()
  • 相关阅读:
    Eureka相关相关接口和代码位置
    Zookeeper(4)---ZK集群部署和选举
    Zookeeper(3)---java客户端的使用
    Zookeeper(2)---节点属性、监听和权限
    玩转百度地图API(地图,坐标,标记,添加控件,2D图,混合图,智能搜索,地址解析器,信息窗口)
    HTML+CSS系列:CSS选择器(标签、ID、类、通配符、后代、子元素、并集、伪类)
    Git系列:常用命令
    Linux系列:快捷键、目录结构、用户目录
    mybatis-plus系统化学习之更新-AR-主键-service
    mybatis-plus系统化学习之查询专题
  • 原文地址:https://www.cnblogs.com/Simon-xm/p/3934584.html
Copyright © 2011-2022 走看看