最早的程序设计方法是面向过程的程序设计,这里的“过程”,其实就是流程。世间有万事,万事各不同,所谓不同,就是流程不同。既然你的程序是针对某个具体的问题,处理的方法和流程当然不同,这样说来,你所精心设计的程序,往往只能解决具体问题,而不具备普遍性和可变性。
面向对象程序设计(ObjectOrientedProgramming,OOP),它是一种程序设计思想,其本质是通过抽象方法建立模型,再将模型具体化的方法。
举一个例子。汽车是一个非常宽泛的概念,大大小小,不同颜色,形态各异的汽车,都属于“汽车”这个类,颜色、轮胎数量、车门个数等属性都是“汽车”类的属性,启动、前进、加速、倒车、刹车等都是“汽车”类的动作(这里的“动作”被称为方法),这些属性和方法既可以指定为具体值,也可以仅仅列出而不赋值。我们也可以定义“汽车”类的一个子类,譬如“红色小轿车”,而一辆具体的车,假如“车号为的”汽车是“红色小轿车”类的一个实例,该汽车便是一个“对象”,该对象除了已经继承了“红色小轿车”类的颜色属性,其他的属性和方法还是继承了父类“汽车”的属性和方法。
综上,面向对象程序设计以对象为核心,该方法认为程序由一系列对象组成。类是对现实世界的抽象,包括表示静态属性的数据和对数据的操作,对象是类的实例化。对象间通过消息传递相互通信,来模拟现实世界中不同实体间的联系。在面向对象的程序设计中,对象是组成程序的基本模块。
面向对象程序设计具有三大基本特征:封装、继承和多态。
下面简要的介绍一下上述提到的名词:
1、对象(Object)
这是一个抽象的概念,“世间万物皆对象”,任何事情和物品都可以用对象来描述。譬如说,在设计学生信息处理程序时,可以将“王小明同学”看成一个研究对象,他有静态属性和动态属性。静态属性有姓名、性别、出生年月(静态属性一般简称为属性)等,动态属性有动作、行为(动态属性一般被称为方法)等。
2、类(class)
一个共享相同结构和行为的对象的集合。类(Class)定义了一类事物(对象)的抽象特点。通常来说,类定义了每个对象共有的属性和方法。举例来说,“学生”这个类会包含了所有学生的一切基础特征,例如籍贯、性别、专业和预约考试、查询成绩。“王小明同学”就是“学生类”的一个实例,是“学生类”的具体化,当然也就继承了“学生类”的全部属性和方法,如他一定有“籍贯、性别、专业”三个属性和“预约考试、查询成绩”两个方法。
3、封装(encapsulation)
封装就是对用户隐藏实现细节。如我们使用手机通话时,关心的是通话的内容,而不需要了解无线电波是如何传播的。此时的手机就是一个黑盒子,我们无须知道其工作原理。
面向对象程序设计中的“封装”,有两层含义:其一是将数据和操作捆绑在一起,创造出一个新的类型的过程;其二是将接口与实现分离的过程。
采用封装思想可以保证类内部数据结构的完整性,使用该类时,用户看不到类中的数据结构,只能通过设计者提供的方法来访问即可,从而提高了程序的可维护性。
4、继承
在日常生活中,继承这个概念适合于长辈与晚辈之间。对于类,也可以分为父类和子类。对象可以继承它从属的类的属性和方法,子类也可以继承父类的属性和方法,
5、多态
有一句俗语说“一龙生九子,九子各不同”。虽然各个子类都继承了父类,但继承的都是共有的属性和方法,而各个子类都有属于自身特有的属性和方法,比如不同专业的学生的课程会不同。
下面举一个例子说明消息传递方面的的多态:比如教师和学生都是用户,都是通过鼠标点击同一个按钮(譬如查看成绩),但进入的界面就不一样,教师看到的是全班所有学生的成绩,而学生看到的只有本人成绩。
6、消息传递
指的是一个对象调用了另一个对象的方法(或者称为成员函数)。
7、方法
也称为成员函数,是指对象上的操作,作为类声明的一部分来定义。方法定义了可以对一个对象执行那些操作。
下面重点介绍类的概念及其应用
1、定义类
具有相同的属性和方法的对象所构成的集合就是类。
语法:
classClassName/p>
statement
其中,ClassName是类名,一般使用大写字母开头,如果类名中包括两个单词,应当采用“驼峰式命名法”,即每个单词的首字母大写,其余字母小写。statement表示类体,包含类变量(或类成员)、方法和属性等定义语句,如果没有类体可以描述,就用pass语句代替。如:
classStudent/p>
pass
这个“空”的类,你可以将其想象为一个“占位符”,虽然它没有实质性的意义,但在以后的编程过程中你可以根据需求去“扩充”它,让它“饱满”。
下面举例说明一个完整的类的语法结构,如:
classStudent/p>
def__init__(self,name,tel)/p>
self.name=name
self.tel=tel
defprint_tel(self)/p>
print(%s:%s%(self.name,self.tel))
这里定义了一个类,类名为Student。__init__()是一个特殊方法(“__”是两个连续的“_”号),类似于Java中的构造方法,每当创建一个类的实例,Python就会自动执行它。其中必须包含参数self,它指向类本身,在实例化时则指向实例本身。上面的Student类的__init__()方法还有两个参数name和tel,实例化时将被具体的实例变量所代替。print_tel()方法访问的类本身的数据,在实例化时也是调用了实例变量。
2、类实例化
类的实例化相当于将类具体化,赋予一组具体的值。和函数调用相似,但又比函数调用复杂。因为类既包含数据,又包含操作数据的方法。
如:
tom=Student(Tom,88)
jim=Student(Jim,)
tom.print_tel()
jim.print_tel()
运行结果:
Tom8
Jim:
可以看出,创建实例是通过类名和()实现的,实例参数要和类属性对应,如’Tom’和类属性name对应,‘88’和类属性tel对应。
tom是Student类的一个实例,它也就能调用类的方法,如tom.print_tel()。如在上面的例子中,添加下面的语句:
tom.name=BaumlR.W
tom.print_tel()
运行结果:
Tom8
Jim:
BaumlR.W8
可见,语句tom.name=BaumlR.W使实例tom的属性name的值发生了改变。
3、私有属性与私有方法
类可以有公有属性与公有方法,也可以有私有属性与私有方法,公有部分的对象可以从外部访问,而私有部分的对象只有在类的内部才可访问。定义私有属性(或方法)时要在的属性名(或方法名)的前面加上两个连续的“_”号。
现在通过下例介绍私有属性与私有方法的用法:
classPubAndPri:
pub=10#此为公有属性
__pri=20#此为私有属性
x=PubAndPri()#x为类PubAndPri的实例
print("publicvar:",x.pub)#通过实例名访问公有属性
print("privatevar:",x.__pri)#通过实例名访问私有属性
运行结果:
publicvar:10
Traceback(mostrecentcalllast):
File"C:/Users/Administrator/AppData/Local/Programs/Python/Python38/2.py",line11,inmodule
print("privatevar:",x.__pri)
AttributeErrorubAndPriobjecthasnoattribute__pri
可见,通过实例名访问私有属性时就会报错。
为了访问私有属性,只能在类中增加一访问私有属性的方法。将上例中的程序修改如下:
classPubAndPri:
pub=10
__pri=20
def__init(self):
print("privatevar:",__pri)#在方法中访问私有属性
x=PubAndPri()
print("publicvar:",x.pub)
print("privatevar:",x._PubAndPri__pri)
#f访问私有属性,格式:实例名._类名__私有属性名(第一个_为一个_,第二个为两个_)
运行结果:
publicvar:10
privatevar:20
由上可以看出,私有属性可以通过“实例名._类名__私有属性名”的方式访问,但在构造方法中要有相关的访问语句。
4、继承与多态
子类可以继承父类的所有公共成员。父类也称基类,子类也称派生类。声明父类的方法是在类名后面的括号中列出。若不声明父类,默认的父类是object。
下面通过一个实例来介绍继承与多态:
程序1:子类完全继承父类
classPerson(object)定义了一个类Person
def__init__(self,name,sex)类Person有两个属性name和sex
self.name=name
self.sex=sex
defprint_info(self)定义了Person类的方法
ifself.sex=="male":
print(self.name+"isman")
elifself.sex=="female":
print(self.name+"iswoman")
classChild(Person)定义了一个子类Child,父类为Person
pass
King=Child("King","male")#创建子类Child的实例
Mary=Person("Mary","female")#创建父类Person的实例
print(King.name+is+King.sex,,Mary.name+is+Mary.sex)
King.print_info()#调用子类Child的print_info方法
Mary.print_info()#调用父类Person的print_info方法
运行结果:
KingismaleMaryisfemale
Kingisman
Maryiswoman
程序2:子类重写父类的方法
classPerson(object)定义了一个类Person
def__init__(self,name,sex):#类Person有两个属性name和sex
self.name=name
self.sex=sex
defprint_info(self):#定义了Person类的方法
ifself.sex=="male":
print(self.name+"isman")
elifself.sex=="female":
print(self.name+"iswoman")
classChild(Person):#定义了一个子类Child,父类为Person
defprint_info(self):#“重写”方法print_info()
ifself.sex=="male":
print(self.name+"isboy")
elifself.sex=="female":
print(self.name+"isgirl")
King=Child("King","male")#子类实例化
Mary=Person("Mary","female")#父类实例化
print(King.name+is+King.sex,,Mary.name+is+Mary.sex)
King.print_info()
Mary.print_info()
输出结果:
KingismaleMaryisfemale
Kingisboy
Maryiswoman
对比程序1和程序2的运行结果可知,程序1中的子类完全继承了父类的属性和方法,程序2中的子类在继承父类的属性和方法的基础上,又对父类的方法进行了重写,从而使子类并不和父类完全相同,这种情况被称为多态,比如程序2中的子类就有不同于父类中的方法print_info(),子类的实例调用的是子类特有的方法,父类的实例调用的是父类的方法。
程序3:子类中重写父类的构造方法
classPerson(object):#定义了一个类Person
def__init__(self,name,sex):#类Person有两个属性name和sex
self.name=name
self.sex=sex
classChild(Person):#定义了一个子类Child,父类为Person
def__init__(self,name,sex,brother,sister):#子类构造方法添加两个属性
Person.__init__(self,name,sex)#继承父类的构造方法
self.brother=brother#添加属性
self.sister=sister#添加属性
King=Child(King,male,Tom,Jane)#创建子类Child的实例
Mary=Person(Mary,female)#创建父类Person的实例
print(King.name,:,King.sex,King.brother,King.sister)
print(Mary.name,:,Mary.sex)
输出结果:
King:maleTomJane
Maryemale
如上,子类在继承父类属性的基础上,可以通过重写构造方法再建立独有的属性。