Python的这种设计是作者从Modula-3中借鉴来的,在后面使用的情况看来,这个设计也是比较成功的。我们对比Python和C++讨论一下这个问题:

Modula-3是上世纪80年代末数字设备公司(DEC)系统研究中心(SRC)和Olivetti研究中心(ORC)设计的一门语言。

尽管这门语言没有在业界广泛的应用起来,但这么语言对后面被发明的Java, Python, Caml, C# 都产生了很多的影响

1.首先,调用的时候要求指定"this",让我们更明确的区分调用的是一个成员变量、函数或者是一个局部变量、函数。

当我们读到self.x或者self.meth(),即使我们不知道class的定义也能100%确定这里调用的是一个成员变量或者方法。我们设想一下,在C++中,我们还可以通过查看并排除所有的局部变量的方式去确认变量是成员变量(假设全局变量很少见,即使出现也是"g_"这种很容易辨认的)。

而在Python中,由于变量不需要额外的定义,这个办法就失效了,唯一的办法就只有看class的定义,所以this就成了必须的。 很多C++和Java的编码规范中会规定成员函数或变量要有m_前缀,我们也可以看到这种编码规范是十分必要的。

2.其次,由于this这个对当前实例的强制显式引用,Python不需要引入任何新的语法就可以引用或者调用其它类(包括父类)的成员变量和函数。

在C++中,如果我们想要在子类中调用父类的函数,我们需要用到::这个运算符;在Python中我们这么写baseclass.methodname(self, <argument list>)。Python的这种语法在实现子类的__init__()时特别有用,例如我们经常需要在子类中override父类的函数并且调用父类函数自身。

3.最后,就是性能上的些许考量:在Python的语言定义中,局部变量就是在函数体中赋值,并且没有在全局显式的声明过的变量。

当然在语言设计上,我们有很多的办法去告诉解释器、编译器某个变量赋值是针对一个局部变量还是一个成员变量,但出于解释性语言的性能考虑,最好是语义上的的规定。C++用变量必须显示的声明解决了这个问题,但Python没有额外的变量声明语法,如果仅仅是出于上面所说的目的引入类似C++的变量必须显式的声明就显得太得不偿失了。

所以,self.var这种语法就是一个非常优美的解决方案。我们在函数里写上self.var这种语法,解释器就不用费力地在全局范围内进行变量的查找。换句话说,局部变量和成员变量存在于两个不同的命名空间,我们需要告诉Python我们用的是哪个空间。

Python学习群:238757010

为什么Python类成员的调用和声明必须有"this"?的更多相关文章

  1. python 类成员函数

    http://cowboy.1988.blog.163.com/blog/static/75105798201091141521583/ 这篇文章总结的非常好 主要注意的地方是 1,在类内调用成员函数 ...

  2. 转:从pickle看python类成员的动态加载和类的定位

      pickle是Python轻便的对象序列化工具.使用pickle可以方便地把python对象写入文件对象中,或者像soap那样在socket间传送.     按照python的一贯作风,类的成员在 ...

  3. 测试Python类成员的单下划线,双下划线,两头下划线的区别

    首先原谅一个菜鸟叫他“两头下划线”.记得在windows编程中,很多宏定义使用下划线+大写,给人逼格很高的错觉.对于Python下划线的认识,大概是从__dict__这个属性开始的,看__dict__ ...

  4. python - 类成员修饰符

    在java,c#类的成员修饰符包括,公有.私有.程序集可用的.受保护的. 对于python来说,只有两个成员修饰符:公有成员,私有成员 成员修饰符是来修饰谁呢?当然是修饰成员了.那么python类的成 ...

  5. python 类成员知识点学习的一个坑(初学者,大神请绕行)

    先来段小程序class Foo: name = "abc" def __init__(self,age): self.age = age print(Foo.name)Foo.na ...

  6. python 类成员的修饰符

    类的所有成员在上一步骤中已经做了详细的介绍,对于每一个类的成员而言都有两种形式: 公有成员,在任何地方都能访问 私有成员,只有在类的内部才能方法 私有成员和公有成员的定义不同:私有成员命名时,前两个字 ...

  7. Python类和实例调用

    self指向的是实例对象,作为第一个参数,使用时不需要传入此参数. class Student(object): #定义一个Student类, def __init__(self, name, sco ...

  8. python 面向对象和类成员和异常处理

    python 面向对象 你把自己想象成一个上帝,你要创造一个星球,首先你要把它揉成一个个球,两个直径就能创造一个球 class star: '''名字(name),赤道直径(equatorial di ...

  9. C#的类成员初始化顺序

    C#的类成员的定义和声明如下 using UnityEngine; using System.Collections; public class TestController : ECControll ...

随机推荐

  1. Spring中的统一异常处理方式

    源自:https://segmentfault.com/a/1190000016236188 在具体的SSM项目开发中,由于Controller层为处于请求处理的最顶层,再往上就是框架代码的. 因此, ...

  2. Linux rpm命令详解

    rpm命令是RPM软件包的管理工具.rpm原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序,由于它遵循GPL规则且功能强大方便,因而广受欢迎.逐渐受到其他发行版的采用.RPM ...

  3. 初识android界面布局

    1.活动 活动是android开发中最基本的概念,也是最容易吸引用户的地方,是一种可以包含用户界面的组件. Activity类中定义了7个回调方法,覆盖了活动生命周期的每一个环节.具体如下: (1)o ...

  4. 【笔记】JS脚本为什么要放在body最后面以及async和defer的异同点

    1.没有defer或async 浏览器遇到脚本的时候会暂停渲染并立即加载执行脚本(外部脚本),"立即"指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的 ...

  5. Java8系列之重新认识HashMap(转)

    原文出处: 前利 简介 Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是HashMap.Hashtable.LinkedHashMap和Tree ...

  6. ali验证码推送接口调用

    /** * 发送接口 * @param $info 发送信息的某些参数 * @return bool */ public function send($info) { $config = target ...

  7. 浏览器地址栏运行JavaScript代码

    这个很多人应该还是知道的,在浏览器地址栏可以直接运行JavaScript代码,做法是以javascript:开头后跟要执行的语句.比如: javascript:alert('hello from ad ...

  8. Sequelize-nodejs-10-Hooks

    Hooks钩子 Hooks (also known as lifecycle events), are functions which are called before and after call ...

  9. print输出

    python中的print输出可以用逗号"," >>> a = 1 >>> b = 2 >>> print a,b 1 2 逗 ...

  10. Python中numpy.random.randn()与rand(),numpy.zeros、ones、eye

    转自:https://blog.csdn.net/u010758410/article/details/71799142