python的新式类和旧式类,见证奇迹的时刻

新式类和旧式类

因为 Python 是一个不断发展的高级语言(似乎别的语言是不断发展的,甚至于自然语言也是),导致了在 Python2.x 的版本中,有“新式类”和“旧式类(也叫做经典类)”之分。新式类是 Python2.2 引进的,在此后的版本中,我们一般用的都是新式类。本着知其然还要知其所以然的目的,简单回顾一下两者的差别。

这是定义了一个非常简单的类,而且是旧式类。至于如何定义类,下面会详细说明。读者姑且囫囵吞枣似的的认同我刚才建立的名为 AA 的类,为了简单,这个类内部什么也不做,就是用 pass 一带而过。但不管怎样,是一个类,而且是一个旧式类(或曰经典类)

然后,将这个类实例化(还记得上节中实例化吗?对,就是那个王美女干的事情):

不要忘记,实例化的时候,类的名称后面有一对括号。接下来做如下操作:

解读一下上面含义:

type(AA):查看类 AA 的类型,返回的是'classobj'

aa.__class__:aa 是一个实例,也是一个对象,每个对象都有__class__属性,用于显示它的类型。这里返回的结果是,从这个结果中可以读出的信息是,aa 是类 AA 的实例,并且类 AA 在内存中的地址是 0xb71f017c。

type(aa):是要看实例 aa 的类型,它显示的结果是'instance,意思是告诉我们它的类型是一个实例。

在这里是不是有点感觉不和谐呢?aa.__class__和 type(aa) 都可以查看对象类型,但是它们居然显示不一样的结果。比如,查看这个对象:

别忘记了,前面提到过的“万物皆对象”,那么一个整数7也是对象,用两种方式查看,返回的结果一样。为什么到类(严格讲是旧式类)这里,居然返回不一样呢?太不和谐了。

于是乎,就有了新式类,从 Python2.2 开始,变成这样了:

终于把两者统一起来了,世界和谐了。

这就是新式类和旧式类的不同。

当然,不同点绝非仅仅于此,这里只不过提到一个现在能够理解的不同罢了。另外的不同还在于两者对于多重继承的查找和调用方法不同,旧式类是深度优先,新式类是广度优先。可以先不理解,后面会碰到的。

不管是新式类、还是旧式类,都可以通过这样的方法查看它们在内存中的存储空间信息

分别告诉了我们两个实例是基于谁生成的,不过还是稍有区别。

知道了旧式类和新式类,那么下面的所有内容,就都是对新式类而言。“喜新厌旧”不是编程经常干的事情吗?所以,旧式类就不是我们讨论的内容了。

还要注意,如果你用的是 Python3,就不用为新式类和旧式类而担心了,因为在 Python3 中压根儿就没有这个问题存在。

如何定义新式类呢?

第一种定义方法,就是如同前面那样:

跟旧式类的区别就在于类的名字后面跟上 (object),这其实是一种名为“继承”的类的操作,当前的类 BB 是以类 object 为上级的(object 被称为父类),即 BB 是继承自类 object 的新类。在 Python3 中,所有的类自然地都是类 object 的子类,就不用彰显出继承关系了。对了,这里说的有点让读者糊涂,因为冒出来了“继承”、“父类”、“子类”,不用着急,继续向下看。下面精彩,并且能解惑。

第二种定义方法,在类的前面写上这么一句:__metaclass__ == type,然后定义类的时候,就不需要在名字后面写(object)了。

两种方法,任你选用,没有优劣之分。

创建类

因为在一般情况下,一个类都不是两三行能搞定的。所以,下面可能很少使用交互模式了,因为那样一旦有一点错误,就前功尽弃。我改用编辑界面。你用什么工具编辑?Python 自带一个 IDE,可以使用。我习惯用 vim。你用你习惯的工具即可。如果你没有别的工具,就用安装 Python 是自带的那个 IDE。

上面定义的是一个比较常见的类,一般情况下,都是这样子的。下面对这个“大众脸”的类一一解释。

新式类

__metaclass__ = type,意味着下面的类是新式类。

定义类

初始化

def __init__,这个函数是一个比较特殊的,并且有一个名字,叫做初始化函数(注意,很多教材和资料中,把它叫做构造函数,这种说法貌似没有错误,但是一来从字面意义上看,它对应的含义是初始化,二来在 Python 中它的作用和其它语言比如 java 中的构造函数还不完全一样,因为还有一个__new__的函数,是真正地构造。所以,在本教程中,我称之为初始化函数)。它是以两个下划线开始,然后是 init,最后以两个下划线结束。

此例子中的初始化函数,就意味着实例化的时候,要给参数 name 提供一个值,作为类初始化的内容。通俗点啰嗦点说,就是在这个类被实例化的同时,要通过 name 参数传一个值,这个值被一开始就写入了类和实例中,成为了类和实例的一个属性。比如:

girl 是一个实例对象,就如同前面所说的一样,它有属性和方法。这里仅说属性吧。当通过上面的方式实例化后,就自动执行了初始化函数,让实例 girl 就具有了 name 属性。

执行这句话的结果是打印出 wangguniang。

这就是初始化的功能。简而言之,通过初始化函数,确定了这个实例(类)的“基本属性”(实例是什么样子的)。比如上面的实例化之后,就确立了实例 girl 的 name 是"wangguniang"。

初始化函数,就是一个函数,所以,它的参数设置,也符合前面学过的函数参数设置规范。比如

这种类型的参数:*args 和前面讲述函数参数一样,就不多说了。忘了的看官,请去复习。但是,self 这个参数是必须的。

很多时候,并不是每次都要从外面传入数据,有时候会把初始化函数的某些参数设置默认值,如果没有新的数据传入,就应用这些默认值。比如:

在编程界,有这样一句话,说“类是实例工厂”,什么意思呢?工厂是干什么的?生产物品,比如生产电脑。一个工厂可以生产好多电脑。那么,类,就能“生产”好多实例,所以,它是“工厂”。比如上面例子中,就有两个实例。

函数(方法)

还是回到本节开头的那个类。构造函数下面的两个函数:def getName(self),def color(self, color),这两个函数和前面的初始化函数有共同的地方,即都是以 self 作为第一个参数。

这个函数中的作用就是返回在初始化时得到的值。

girl.getName()就是调用实例 girl 的方法。调用该方法的时候特别注意,方法名后面的括号不可少,并且括号中不要写参数,在类中的 getName(self) 函数第一个参数 self 是默认的,当类实例化之后,调用此函数的时候,第一个参数不需要赋值。那么,变量 name 的最终结果就是 name = "wangguniang"。

同样道理,对于方法:

也是在实例化之后调用:

这也是在执行实例化方法,只是由于类中的该方法有两个参数,除了默认的 self 之外,还有一个 color,所以,在调用这个方法的时候,要为后面那个参数传值了。

至此,已经将这个典型的类和调用方法分解完毕,把全部代码完整贴出,请读者在从头到尾看看,是否理解了每个部分的含义:

保存后,运行得到如下结果:

类和实例

有必要总结一下类和实例的关系:

“类提供默认行为,是实例的工厂”(源自 Learning Python),这句话非常经典,一下道破了类和实例的关系。所谓工厂,就是可以用同一个模子做出很多具体的产品。类就是那个模子,实例就是具体的产品。所以,实例是程序处理的实际对象。

类是由一些语句组成,但是实例,是通过调用类生成,每次调用一个类,就得到这个类的新的实例。

对于类的:class Person,class 是一个可执行的语句。如果执行,就得到了一个类对象,并且将这个类对象赋值给对象名(比如 Person)。

也许上述比较还不足以让看官理解类和实例,没关系,继续学习,在前进中排除疑惑。

self 的作用

如果将上面的类稍加修改,看看效果:

其它部分省略。当初始化的时候,就首先要运行构造函数,同时就打印新增的两条。结果是:

证实了推理。self 就是一个实例(准确说是实例的引用变量)。

self 这个实例跟前面说的那个 girl 所引用的实例对象一样,也有属性。那么,接下来就规定其属性和属性对应的数据。上面代码中:

就是规定了 self 实例的一个属性,这个属性的名字也叫做 name,这个属性的值等于初始化函数的参数 name 所导入的数据。注意,self.name 中的 name 和初始化函数的参数 name 没有任何关系,它们两个一样,只不过是一种起巧合(经常巧合,其实是为了省事和以后识别方便,故意让它们巧合。),或者说是写代码的人懒惰,不想另外取名字而已,无他。当然,如果写成 self.xxxooo = name,也是可以的。

其实,从效果的角度来理解,这么理解更简化:类的实例 girl 对应着 self,girl 通过 self 导入实例属性的所有数据。

当然,self 的属性数据,也不一定非得是由参数传入的,也可以在构造函数中自己设定。比如:

运行结果

通过这个例子,其实让我们拓展了对 self 的认识,也就是它不仅仅是为了在类内部传递参数导入的数据,还能在初始化函数中,通过 self.attribute 的方式,规定 self 实例对象的属性,这个属性也是类实例化对象的属性,即做为类通过初始化函数初始化后所具有的属性。所以在实例 info 中,通过 info.email 同样能够得到该属性的数据。在这里,就可以把 self 形象地理解为“内外兼修”了。或者按照前面所提到的,将 info 和 self 对应起来,self 主内,info 主外。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180226A1CS9Q00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券