第8章 类基础
有的资料将这一章内容命名为“面向对象”,虽然没有错误,但这并不很 Pythonic ,因为 Python 中的函数是第一类对象,在前一章中已经开始“面向对象”了。其实不仅仅是第7章,本书从一开始,就在“面向对象”。那么,本章的类与对象有什么关系?为什么很多自学者会在学到本章的时候遇到困难?如何跨过这个难关?请读者满怀信心地认真学习本章和第9章,严格地执行各项学习建议。“漫卷诗书喜欲狂”的成功愉悦就在不远的将来。
8.1 面向对象
在第2章2.4节曾初步了解过“对象”的概念,并且通过前面各章节的学习,读者已经对 Python 中的对象,比如内置对象和作为第一类对象的函数有了初步基本认识。从现在开始,将要在原有基础上,更深入地理解对象。
8.1.1 对象和面向对象
“对象”虽然是计算机科学中的专业术语,但不同的资料对其表述略有不同,例如《维基百科》中关于“对象”的词条内容是“对象(Object),台湾译作物件,是面向对象(Object Oriented)中的术语,既表示客观世界问题空间中的某个具体的事物,又表示软件系统解空间中的基本元素。”
计算机科学家 Grandy Booch(被业界尊为“面向对象”领域中的大师)所定义的“对象”包括以下要点:
- 对象:一个对象有自己的状态、行为和唯一的标识;所有相同类型的对象所具有的结构和行为在它们共同的类中被定义。
- 状态(State):包括这个对象已有的属性(通常是类里面已经定义好的),再加上对象具有的当前属性值(这些属性往往是动态的)。
- 行为(Behavior):是指一个对象如何影响外界及被外界影响,表现为对象自身状态的改变和信息的传递。
- 标识(Identity):是指一个对象所具有的区别于所有其他对象的属性。
将上述要点可以概括为:对象应该具有属性(即“状态”)、方法(即“行为”)和标识。Python 中对象的标识即在创建对象的时候自动在内存空间提供存储地址,所以,平时编写程序主要关注的是属性和方法。在第2章2.4节曾通俗地说明了 Python 语言对象的属性和方法的含义:
- 属性——描述对象“是什么”。
- 方法——描述对象“能干什么”。
再来看“面向对象”是什么意思,这是现在编程的主流思潮。还是引用《维基百科》中词条内容:
面向对象程序设计(Object-oriented Programming,OOP)是一种程序设计范式,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。
在此,对“面向对象”的理解姑且局限于这个表述。既然它是一种编程方法,就必须在编程实践中才能理解其真谛——实践出真知。所以,在后续的内容中,我们所学习和练习的,都是以“面向对象”为基本思想和方法——其实前面的学习和练习也如此,只是没有特别强调罢了。
8.1.2 类
编程语言中所说的“类”,其英文是“class”,“类”是中文翻译名称。对于初学者而言,听到这个名词会感觉怪怪的,因为不是很符合现代汉语的习惯。在汉语中,常说“鸟类”、“人类”等词语。当然,作为专门术语,不是不行,只是不太习惯罢了。诚然,在计算机科学中,类似的翻译还有不少,造成这种现象的原因很多,建议读者以“英汉结合”的方式来理解。
在目前流行的高级编程语言中,类是必须的。借用《维基百科》的定义:“在面向对象程序设计中,类(class)是一种面向对象计算机编程语言的构造,是创建对象的蓝图,描述了所创建的对象共同的属性和方法。”
据此定义,重点理解:
- “蓝图”,一种比喻说法,意思是根据“类”可以得到对象。这就好比一个汽车制造工厂,有了一个生产汽车的设计(包含图纸和生产线),根据这个设计就可以生产出很多汽车。“设计”(或“蓝图”)就相当于“类”,而“汽车”就相当于根据“类”而创建的“对象”——也称之为“实例”,这个过程叫做“实例化”或者“创建实例”(如图8-1-1所示)。
- 在“类”中,要定义“属性”和“方法”。
图8-1-1 类与蓝图的对比
“工厂中汽车的设计”绝对不是白纸一张,其中规定很多关于未来要造出来的“汽车对象”的“属性”和“方法”,比如车的颜色、车的性能等。如果抽象来看“类”,也是如此,要在类中规定好将来“造出来”的“实例们”所共有的属性和方法。
例如,把江湖上的一等一的大侠高手们的特点总结一下,发现他们有很多共同之处(以下皆为杜撰,若有雷同,纯属巧合,请勿对号入座):
- 都会“九阴真经”;
- 都吃过毒蛤蟆或者被毒蛇咬过,因此“百毒不侵”;
- 都不是单身;
- 都是男的;
- 都不使用阴招。
假设达到这个标准——“蓝图”——就是大侠,那么在写小说的时候,给某个人物赋予上述各项内容——创建实例,就塑造出来了一位大侠。
为了让生产“大侠”的过程更“数学”化,需要在表述上精准,所以把上述大侠的各项特征写到“类”里面——设计“蓝图”。用类似 Python语言的代码可以这样写:
代码语言:javascript复制class 大侠:
性别 = 男
是否单身 = 否
中毒 = 百毒不侵
是否阴狠 = 否
九阴真经()
在这个名为“大侠”的类中,有属性——描述大侠的特征,即“是什么”,如:性别 = 男
。“性别”是属性,“男”是此属性的值。还有“方法”——描述大侠会什么功夫,即“做什么”,用形如“九阴真功()”的方式表示,类似前面学习过的函数,表示它可以被调用——功夫当然是要用来执行的。
接下来就可以用所定义的类“生产”大侠——不是文学作品中塑造大侠,而是用编程语言创建大侠“实例”。
代码语言:javascript复制laoqi = 大侠()
我们所使用的符号体系与上一章中函数雷同,大侠
也是名称——类的名称——后面紧跟一对圆括号 ()
,表示要执行这个名称所引用的对象,即“执行类”,可以形象地理解为让“工厂的生产线按照蓝图运行起来”,结果就应该是生产出产品了。于是由 大侠()
可得到“一个具体的大侠”——实例,并将该实例对象用变量 laoqi
引用,也可以简单说成实例 laoqi
。
如此,在程序中创建了一个符合“大侠类”中设计规范的“真实的大侠”实例——laoqi
。那么这个大侠的属性怎么访问?先想想以前学过的内置对象属性怎么访问?基本格式是“对象.属性”(注意中间的英文状态的符号),然后得到它的值。对实例 laoqi
也是如此,例如:
>>> laoqi.中毒 # (1)
百毒不侵
注释(1)表示请求属性“中毒”的值,所返回的“百毒不侵”即是类中规定的此属性的值。任何用这个类所创建的大侠,其“中毒”的属性默认值都是“百毒不侵”。
还可以使用大侠具有的武功:
代码语言:javascript复制>>> laoqi.九阴真经()
上述只是“伪装成”代码来演示。真正在 Python 中定义类,自有其严格规定。