add by zhj:今天在学习SimpleHTTPServer的源代码时,看到了Python标准库SocketServer模块中有个BaseServer类,该类的__init__方法定义如下

    def __init__(self, server_address, RequestHandlerClass):
"""Constructor. May be extended, do not override."""
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False

看到它的注释写着,该类不能override。在初始化时,它定义了__is_shut_down和__shutdown_request两个变量,我之前对__xx这样的变量的含义不理解,

现在联想到会不会是这种变量不能被子类override呢?然后查到了下面这篇文章,果然如此。Python已经从解释器层面考虑到了这种私有变量,保证了这种

变量不会被子类的同名变量覆盖,很牛逼,这样的话,其实子类就完全没有必要再定义同名的__xx变量了,因为即使定义了,也不能覆盖父类中的同名变量,

而且这样写易读性很差,很容易让人搞混。Python这个trick做得还是挺不错的。其实,之前对__xx变量的含义也有了解,但当时只思考它的工作原理,并不

理解它这样做到底是为了什么,回头想想:当时自己本末倒置了,如果先知道这样做的目的,再理解原理就更容易些。

原文:未找到

引子
我热情地邀请大家猜测下面这段程序的输出:
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.__private()”开始。但要讲清楚为什么,我们就有必要了解一下Python的命名机制。
据 Python manual,变量名(标识符)是Python的一种原子元素。当变量名被绑定到一个对象的时候,变量名就指代这个对象,就像人类社会一样,不是吗?当变 量名出现在代码块中,那它就是本地变量;当变量名出现在模块中,它就是全局变量。模块相信大家都有很好的理解,但代码块可能让人费解些。在这里解释一下:
代码块就是可作为可执行单元的一段Python程序文本;模块、函数体和类定义都是代码块。不仅如此,每一个交互脚本命令也是一个代码块;一个脚本文件也是一个代码块;一个命令行脚本也是一个代码块。
接下来谈谈变量的可见性,我们引入一个范围的概念。范围就是变量名在代码块的可见性。 如果一个代码块里定义本地变量,那范围就包括这个代码块。如果变量定义在一个功能代码块里,那范围就扩展到这个功能块里的任一代码块,除非其中定义了同名 的另一变量。但定义在类中的变量的范围被限定在类代码块,而不会扩展到方法代码块中。
迷踪
据上节的理论,我们可以把代码分为三个代码块:类A的定义、类B的定义和变量b的定义。根据类定义,我们知道代码给类A定义了三个成员变量(Python的函数也是对象,所以成员方法称为成员变量也行得通。);类B定义了两个成员变量。这可以通过以下代码验证:
>>> print '\n'.join(dir(A))
_A__private
__init__
public
>>> print '\n'.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 '\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()”吧!
真相
相信现在聪明的读者已经猜到答案了吧?如果你还没有想到,我给你个提示:真相跟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()

理解Python的双下划线命名(转)的更多相关文章

  1. 理解Python的双下划线命名

    引子 我热情地邀请大家猜测下面这段程序的输出: class A(object):        def __init__(self):               self.__private()   ...

  2. 详解 Python 中的下划线命名规则

    在 python 中,下划线命名规则往往令初学者相当 疑惑:单下划线.双下划线.双下划线还分前后……那它们的作用与使用场景 到底有何区别呢?今天 就来聊聊这个话题. 1.单下划线(_) 通常情况下,单 ...

  3. python面向对象双下划线方法与元类

    目录 双下划线方法(__) 元类简介 产生类的两种表现形式 元类的基本使用 元类进阶操作 __new__方法 双下划线方法(__) 面向对象中的双下方法也有一些人称之为是魔法方法,有些双下方法不需要刻 ...

  4. python单/双下划线使用

    在Python编程中经常会遇到函数(function),方法(method)及属性(attribute)以下划线'_'作为前缀,这里做个总结. 主要存在四种情形: 1. object # public ...

  5. python 类 双下划线解析

    __getattr__用法:说明:这是python里的一个内建函数,当调用的属性或者方法不存在时,该方法会被调用调用不存在的属性调用不存在的方法

  6. python——双下划线与python命名机制

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

  7. Python 的类的下划线命名有什么不同?

    1.   以一个下划线开头的命名 ,如_getFile2.  以两个下划线开头的命名 ,如__filename3.  以两个下划线开头和结尾的命名,如 __init__()4.  其它 单下划线前缀的 ...

  8. python中单下划线和双下划线的区别

    1.python中双下划线(__str__)代表这个变量是特殊变量,是可以直接访问的 __xxx___ 定义的是特列方法.像__init__之类的 2.python前面双划线(__name)代表这个变 ...

  9. Python中的下划线(译文)

    原文地址这篇文章讨论Python中下划线_的使用.跟Python中很多用法类似,下划线_的不同用法绝大部分(不全是)都是一种惯例约定. 单个下划线(_) 主要有三种情况: 1. 解释器中 _符号是指交 ...

随机推荐

  1. TCP/IP模型及OSI七层参考模型各层的功能和主要协议

    注:网络体系结构是分层的体系结构,学术派标准OSI参考模型有七层,而工业标准TCP/IP模型有四层.后者成为了事实上的标准,在介绍时通常分为5层来叙述但应注意TCP/IP模型实际上只有四层. 1.TC ...

  2. 安卓程序代写 网上程序代写[原]Android应用的自动更新模块

    软件的自动更新一般都与Splash界面绑定在一起, 由于需要维护的软件界面很复杂, 一个Activity中嵌入ViewPager, 并且逻辑比较复杂, 索性重新写一个Activity, 现在的软件都很 ...

  3. Fedora Server 21 安装 搜狗拼音输入法

    最新文章:Virson’s Blog 借鉴文章:博客园-怒杀神殿    ChinaUnix-firo 百度贴吧-fedora吧 方法一:解压deb安装包方式安装: 如果本机已安装ibus,需要先卸载, ...

  4. JAVA基础知识点总结(全集)

    1.JAVA简介 1.1java体系结构:j2se,javaweb,j2ee 1.2java特点:平台无关(虚拟机),垃圾回收(使得java更加稳定) 1.3 JDK与JRE,JDK:java开发环境 ...

  5. talk is cheap, show me the code——dcgan,wgan,wgan-gp的tensorflow实现

    最近学习了生成对抗网络(GAN),基于几个经典GAN网络结构做了些小实验,包括dcgan,wgan,wgan-gp.坦率的说,wgan,wgan-gp论文的原理还是有点小复杂,我也没有完全看明白,因此 ...

  6. [Android] Java Basic : preview

    基础教学:lecture, video, lecturer: Matt Stoker Java教学:http://www.runoob.com/java/java-intro.html[菜鸟教程,非常 ...

  7. actor 内最好不要阻塞

    1. 在使用 akka cluster singleton 时,我需要知道被创建的 singleton proxy 的 actorRef,通过绝对路径加 actorSelection 方法,应该很容易 ...

  8. Phoenix系列:原子的Upsert

    Phoenix的插入语句是Upsert,Update和Insert的组合语义.即,如果数据表中没有这条记录那么插入这条记录,如果有则更新.判断是否存在相同的数据是使用ON DUPLICATE KEY来 ...

  9. apache 设置环境变量

    在apache设置环境变量有什么好处: 提高代码的可移植性,不用因为换服务器而改项目代码

  10. 校验字符串是否是JSON格式,将不规则展示的json格式的字符串进行规则展示(json格式化)

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   var str = {"code": "","svcname" ...