Python 核心编程(第二版)——面向对象编程
1.介绍
如何创建一个类?关键字是class,紧接着是一个类名。随后是定义类的类体代码。ex:
python;gutter:true;">class MyNewObjectType(bases):\'define MyNewObjectType class\'
class_suite #类体
新式类和经典类声明的最大不同在于,所有新式类必须继承至少一个父类,参数bases可以是一个(单继承)或多个(多重继承)用于继承的父类。
object 是“所有类之母”。如果你的类没有继承任何其他父类,object 将作为默认的父类。它位于所有类继承结构的最上层。如果你没有直接或间接的子类化一个对象,那么你就定义了一个经典类:
class MyNewObjectType:\'define MyNewObjectType classic class\'
class_suite
如果你没有指定一个父类,或者如果所子类化的基本类没有父类,你这样就是创建了一个经典类。
创建一个实例的过程称作实例化,过程如下(注意:没有使用new 关键字):
myFirstObject = MyNewObjectType()
类名使用我们所熟悉的函数操作符(()),以“函数调用”的形式出现。然后你通常会把这个新建的实例赋给一个变量。赋值在语法上不是必须的,但如果你没有把这个实例保存到一个变量中,它就没用了,会被自动垃圾收集器回收,因为任何引用指向这个实例。
注意有的地方在语法构成上需要有一行语句,但实际上不需要做任何操作,这时候可以使用pass语句。
方法——在Python中,方法定义在类定义中,但只能被实例所调用。也就是说,调用一个方法的最终途径必须是这样的:(1)定义类(和方法),(2)创建一个实例(3)最后一步,用这个实例调用方法。
class MyDataWithMethod(object): # 定义类def printFoo(self): # 定义方法
print \'You invoked printFoo()!\'
注意:self 参数,它在所有的方法声明中都存在,这个参数代表实例对象本身。
在Python 中,Python 创建实例后,在实例化过程中,调用__init__()方法,当一个类被实例化时,就可以定义额外的行为。
1 创建一个类(类定义)2 class AddrBookEntry(object): # 类定义
3 \'address book entry class\'
4
5 def __init__(self, nm, ph): # 定义构造器
6 self.name = nm # 设置 name
7 self.phone = ph # 设置 phone
8 print \'Created instance for:\', self.name
9
10 def updatePhone(self, newph): # 定义方法
11 self.phone = newph
12 print \'Updated phone# for:\', self.name
View Code
创建实例(实例化)>>> john = AddrBookEntry(\'John Doe\', \'408-555-1212\') #为John Doe 创建实例
>>> jane = AddrBookEntry(\'Jane Doe\', \'650-555-1212\') #为Jane Doe 创建实例
实例化调用,它会自动调用__init__()。self 把实例对象自动传入__init__()。你可以在脑子里把方法中的self 用实例名替换掉。如果不存在默认的参数,那么传给__init__()的两个参数在实例化时是必须的。
创建子类——靠继承来进行子类化是创建和定制新类类型的一种方式,新的类将保持已存在类所有的特性,而不会改动原来类的定义(指对新类的改动不会影响到原来的类,译者注)。对于新的类类型来说,这个新的子类可以定制只属于它的特定功能。
如果需要,每个子类最好定义它自己的构造器,不然,基类的构造器会被调用。然而,如果子类重写基类的构造器,基类的构造器就不会被自动调用了--这样,基类的构造器就必须显式写出才会被执行。
核心笔记:命名类、属性和方法
类名通常由大写字母打头。这是标准惯例,可以帮助你识别类,特别是在实例化过程中(有时看起来像函数调用)。还有,数据属性(译者注:变量或常量)听起来应当是数据值的名字,方法名应当指出对应对象或值的行为。另一种表达方式是:数据值应该使用名词作为名字,方法使用谓词(动词加对象)。数据项是操作的对象、方法应当表明程序员想要在对象进行什么操作。Python 规范推荐使用骆驼记法的下划线方式。
2. 面向对象编程
面向对象编程思想(OOP)、面向对象设计(object-oriented design,OOD)
抽象/实现:抽象指对现实世界问题和实体的本质表现,行为和特征建模,建立一个相关的子集,可以用于描绘程序结构,从而实现这种模型。抽象不仅包括这种模型的数据属性,还定义了这些数据的接口。对某种抽象的实现就是对此数据及与之相关接口的现实化(realization)。现实化这个过程对于客户程序应当是透明而且无关的。
封装/接口:封装描述了对数据/信息进行隐藏的观念,它对数据属性提供接口和访问函数。
合成:合成扩充了对类的描述,使得多个不同的类合成为一个大的类,来解决现实问题。合成描述了一个异常复杂的系统,比如一个类由其它类组成,更小的组件也可能是其它的类,数据属性及行为,所有这些合在一起,彼此是“有一个”的关系。
派生/继承/继承结构:派生描述了子类的创建,新类保留已存类类型中所有需要的数据和行为,但允许修改或者其它的自定义操作,都不会修改原类的定义。继承描述了子类属性从祖先类继承这样一种方式。
泛华/特化:泛化表示所有子类与其父类及祖先类有一样的特点,所以子类可以认为同祖先类是“是一个”的关系,因为一个派生对象(实例)是祖先类的一个“例子”。
多态:多态的概念指出了对象如何通过他们共同的属性和动作来操作及访问,而不需考虑他们具体的类。多态表明了动态(又名,运行时)绑定的存在,允计重载及运行时类型确定和验证。
自省/反射:自省表示给予你,程序员,某种能力来进行像“手工类型检查”的工作,它也被称为反射。这个性质展示了某对象是如何在运行期取得自身信息的。
3. 类
在Python 中,类声明与函数声明很相似,头一行用一个相应的关键字,接下来是一个作为它的定义的代码体,如下所示:
def functionName(args):\'function documentation string\' #函数文档字符串
function_suite #函数体
class ClassName(object):
\'class documentation string\' #类文档字符串
class_suite #类体
二者都允许你在他们的声明中创建函数,闭包或者内部函数(即函数内的函数),还有在类中定义的方法。最大的不同在于你运行函数,而类会创建一个对象。类就像一个Python 容器类型。类还允许派生。你可以创建一个子类,它也是类,而且继续了父类所有的特征和属性。
创建类:Python 类使用class 关键字来创建。简单的类的声明可以是关键字后紧跟类名:
class ClassName(bases):\'class documentation string\' #\'类文档字符串\'
class_suite #类体
基类是一个或多个用于继承的父类的集合;类体由所有声明语句,类成员定义,数据属性和函数组成。类通常在一个模块的顶层进行定义,以便类实例能够在类所定义的源代码文件中的任何地方被创建。
声明与定义:对于Python 函数来说,声明与定义类没什么区别,因为他们是同时进行的,定义(类体)紧跟在声明(含class 关键字的头行[header line])和可选(但总是推荐使用)的文档字符串后面。同时,所有的方法也必须同时被定义。
4. 类属性
什么是属性呢?属性就是属于另一个对象的数据或者函数元素,可以通过我们熟悉的句点属性标识法来访问。属性的一个有趣的地方是,当你正访问一个属性时,它同时也是一个对象,拥有它自己的属性,可以访问,这导致了一个属性链。类属性仅与其被定义的类相绑定。
类的数据属性——数据属性仅仅是所定义的类的变量。它们可以像任何其它变量一样在类创建后被使用,并且,要么是由类中的方法来更新,要么是在主程序其它什么地方被更新。
静态变量(静态数据)表示这些数据是与它们所属的类对象绑定的,不依赖于任何类实例。
决定类的属性——要知道一个类有哪些属性,有两种方法。最简单的是使用dir()内建函数。另外是通过访问类的字典属性__dict__,这是所有类都具备的特殊属性之一。
特殊的类属性
特殊类属性 | |
C.__name__ | 类C的名字(字符串) |
C.__doc__ | 类C的文档字符串 |
C.__bases__ | 类C的所有父类构成的元组 |
C.__dict__ | 类C的属性 |
C.__module__ | 类C定义所在的模块(1.5 版本新增) |
C.__class__ | 实例C对应的类(仅新式类中) |
__name__是给定类的字符名字。它适用于那种只需要字符串(类对象的名字),而非类对象本身的情况。甚至一些内建的类型也有这个属性。
__doc__是类的文档字符串,与函数及模块的文档字符串相似,必须紧随头行(header line)后的字符串。文档字符串不能被派生类继承,也就是说派生类必须含有它们自己的文档字符串。
__bases__用来处理继承,它包含了一个由所有父类组成的元组。
__dict__属性包含一个字典,由类的数据属性组成。访问一个类属性的时候,Python 解释器将会搜索字典以得到需要的属性。如果在__dict__中没有找到,将会在基类的字典中进行搜索,采用“深度优先搜索”顺序。基类集的搜索是按顺序的,从左到右,按其在类定义时,定义父类参数时的顺序。对类的修改会仅影响到此类的字典;基类的__dict__属性不会被改动的。
Python 支持模块间的类继承。引入__module__,这样类名就完全由模块名所限定。
5. 实例
>>> class MyClass(object): # define class 定义类... pass
>>> mc = MyClass() # instantiate class 初始化类
仅调用("calling")类:MyClass(),就创建了类MyClass 的实例mc。返回的对象是你所调用类的一个实例。
__init__() "构造器" 方法——当类被调用,实例化的第一步是创建实例对象。一旦对象创建了,Python 检查是否实现了__init__()方法。默认情况下,如果没有定义(或覆盖)特殊方法__init__(),对实例不会施加任何特别的操作.任何所需的特定操作,都需要程序员实现__init__(),覆盖它的默认行为。如果__init__()没有实现,则返回它的对象,实例化过程完毕。如果__init__()已经被实现,那么它将被调用,实例对象作为第一个参数(self)被传递进去,像标准方法调用一样。调用类时,传进的任何参数都交给了__init__()。
与__init__()相比,__new__()方法更像一个真正的构造器。为何我们认为__new__()比__init__()更像构造器呢?这是因为__new__()必须返回一个合法的实例,这样解释器在调用__init__()时,就可以把这个实例作为self 传给它。调用父类的__new__()来创建对象,正像其它语言中使用new 关键字一样。
有一个相应的特殊解构器(destructor)方法名为__del__()。然而,由于Python 具有垃圾对象回收机制(靠引用计数),这个函数要直到该实例对象所有的引用都被清除掉后才会执行。
要注意,解构器只能被调用一次,一旦引用计数为0,则对象就被清除了。这非常合理,因为系统中任何对象都只被分配及解构一次。
总结:
以上是 Python 核心编程(第二版)——面向对象编程 的全部内容, 来源链接: utcz.com/z/388299.html