一、前言
面向对象是一种设计哲学和方法论。它并非必需,不使用面向对象也可以编程。但有了面向对象,可以把程序组织得更有条理,让设计过程更加愉悦和轻松。面向对象:再解决问题的时候关注的是解决问题所需要的对象。
Python是一种面向对象的高级语言。实际上,面向对象的编程方式是由面向过程的编程方式发展而来的。可以说,面向对象的编程是高级语言发展的第二发展阶段。第二发展阶段的面向对象的高级语言比第一阶段的面向过程的高级语言,具有更强的灵活性与可扩展性,目前,占据主流地位。本章中,首先将介绍类与对象到底是什么;然后介绍面向对象的编程语言。(面向对象本身是面向过程的封装)
面向过程:按照步骤划分;把一个任务,分解成具体的每一个步骤。
面向对象:按照功能对象进行划分;找到对象,确定对象属性和行为。
面向对象保证了功能的统一性。例如,五子棋游戏要加入悔棋的功能,基于面向过程思想开发的程序需要改动输入、判断、显示等一系列步骤,甚至还要大规模地调整步骤之间的逻辑,这显然是非常麻烦的;在基于面向对象思想进行开发时,因为棋盘对象保存了游戏的画面,所以仅仅给棋盘对象增加回溯行为,玩家和规则系统对象不需要做任何调整。由此可见,面向对象编程更便于后续代码的维护和功能扩展。
二、类与对象的概念
类是一个模板,一张蓝图。根据同一模板或蓝图可以创建出很多的具体实例。尽管这些实例可以有自己独特的特点,但是这些实例都是同一类东西,都是根据同一个模板或者蓝图创造出来的。这些实例可以被称为对象。所谓面向对象的编程,就是首先研究实例对象,抽象提炼出这些对象的特征属性,与特征行为,生成类。再以类为模板,生成一个又一个实例,最后针对一个又一个的实例对象进行编程。
对象映射了现实生活中真实存在的事务,它可以看得见摸得着,,例如,你现在手里的这本书就是一个对象;类是抽象的,它是对一群具有相同特征和行为的事务的统称,例如,“书是人类进步的阶梯”中提到的书并不具体指哪本书,它就是一个类。
关系: 对象可以抽象为类 类可以实例化为对象
在Python中所有类型都是类,如:int,float,bool,str等等。如果想知道自己操作的数据是什么类型的,可以使用内置函数type()。
通过type()内置函数验证数据类型。
print(type(True))
print(type(2.3))
print(type(2))
print(type("hello"))
print(type([2,3,4]))
print(type({2,3,4}))
# <class 'bool'>
# <class 'float'>
# <class 'int'>
# <class 'str'>
# <class 'list'>
# <class 'set'>
所有的面向对象的编程语言,都可以使用面问过程的编程方式。对于一般的程序员来说,更希望采用面向对象的编程方式:
(1)定义一个类,创建一个模板或者蓝图:
(a)抽象出类中的特征属性
(b)抽象出类的行为方法
(2)创建类实例,针对实例对象进行编程。
三、定义类的方法
一般形式:
class 类名:
属性名=属性值
def 方法名(self):
方法体
属性类似于前面章节中所学的变量,方法类似于前面章节中所学的函数;
方法参数列表中的第一个参数是一个指代对象的默认参数self。
下面定义一个表示轿车的Car类,该类中包含描述轿车车轮数量的属性wheels和描述轿车行驶行为的方法drive()。
class Car:
wheels=4 #公共属性
def drive(self):
print("行驶")
c1=Car()
c2=Car()
print(c1.wheels,c2.wheels)
Car.wheels=2
print(c1.wheels,c2.wheels)
凡是人类,皆有姓名、性别、身高、体重等性质,这些性质被称为类型的属性(attribute),有时也称为数据成员(data member)。
人还能做很多事情,例如说话(speak)、进食(eat)、思考(think)、学习(learn)等,这些行为是这个类型的方法(method),也可以叫成员函数(member function)。
在Python中,使用class关键字来定义一个类。它的一般语法如下:
class 类名:
定义构造函数
……
定义类属性
……
定义类函数
在创建类时,我们可以手动添加一个 “__init __() ”方法,该方法是一个特殊的方法,被称为构造函数(或构造方法)。构造函数在创建实例对象时被使用,每创建一个类的实例对象时,Python都会自动调用构造函数。一般说来,类名使用大写字母开头的驼峰命名法,类中的属性名与函数名,使用小写字母开头的驼峰命名法。
Python类中,构造函数的语法格式如下:
def __init__ (self,属性列表):
程序块
……
此处需要特别指出,由于打印问题,可能看到的是,在此函数的函数名中init的前后各有一条下划线。但是实际上,init开头和结尾是各有 2 条下划线,且中间没有空格。
“__init __() ”函数可以包含多个参数,但必须包含1个名为 self的参数,且必须作为第一个参数。也就是说,类的构造函数最少要有一个 self 参数。仅包含 self 参数的“__init__(self)”构造函数,称为默认构造函数。
类是一个模板,同一个类可以产生多个对象。当某个对象调用类函数时,该对象会把自身的引用作为第一个参数自动传给该函数,因此这些函数可以被称为是实例函数(或者对象函数)。“self”参数的具体作用是:将自身传递给实例函数。
每个类默认都有一个__init__()方法,如果一个类中显式地定义了__init__()方法,那么创建对象时调用显式定义的__init__()方法;否则调用默认的__init__()方法。
__init__()方法可以分为无参构造方法和有参构造方法。
(1)当使用无参构造方法创建对象时,所有对象的属性都有相同的初始值。
(2)当使用有参构造方法创建对象时,所有对象的属性可以有不同的初始值。
下面定义一个包含无参构造方法和实例方法drive()的Car类,分别创建2个Car类的对象car_one和car_two,通过对象car_one和car_two调用drive()方法,示例代码如下:
class Car:
def __init__(self):
self.color="红色"
def drive(self):
print("车的颜色是"+str(self.color))
car_one=Car()
car_one.drive()
car_two=Car()
car_two.drive()
class Car:
def __init__(self,color):
self.color=color #属性值和实例绑定
def drive(self):
print("车的颜色是"+str(self.color))
car_one=Car("红色")
car_one.drive()
car_two=Car("蓝色")
car_two.drive()
Python类中,定义类行为(可以被称为方法或函数)的语法格式如下:
def 函数名(self,属性列表):
程序块
……
设计一个名为Food的简单的类。这个类包含两个属性,用来记录信息。这两个属性分别为name与cal,代表食物名,以及食物的热量。
class Food:#关键字class表明,此处开始,定义了一个类,类名为Food。
def __init__(self, name, cal):#定义了一个构造函数。这个构造函数的参数,有三个,分别为self、name和cal,“__init __() ”函数中的name和cal是这个类的两个属性
self.name = name
self.cal = cal
def eat(self):#第6至第10行,定义了一个类函数,用来返回信息
print("\t每百克的" + self.name + "具有" \
+ str(self.cal) + "卡路里的热量")
return self.cal
p1=Food('蛋糕',100)
p1.eat()
四、对象及对象的使用
创建对象的语法格式如下所示:
对象名=类名()
对象的使用本质上就是对类对象成员的使用,即访问属性或调用方法。访问属性或调用方法的语法格式如下:
对象名.属性名
对象名.方法名()
class Car:
wheels=4
def drive(self):
print("行驶")
car=Car()
print(car.wheels)
print(car.drive())
类的成员包括属性和方法,默认它们可以在类的外部被访问或调用,但考虑到数据安全问题,有时需要将其设置为私有成员,限制在类外部对其进行访问或调用。
属性按声明的方式可以分为两类:类属性和实例属性。
1.类属性
类属性是声明在类内部、方法外部的属性。例如实例中Car类内部声明的wheels属性就是一个类属性。类属性可以通过类或对象进行访问,但只能通过类进行修改。
2.实例属性
实例属性是在方法内部声明的属性,Python支持动态添加实例属性。下面从访问实例属性、修改实例属性和动态添加实例属性3个方面对实例属性进行介绍。
(1) 访问实例属性
实例属性只能通过对象进行访问(不能通过类访问)。例如,定义一个包含方法和实例属性的类Car,创建Car类对象,并访问实例属性,代码如下:
class Car:
def drive(self):
self.wheels=4
car=Car()
print(car.drive())
print(car.wheels)
print(Car.wheels)
(2)修改实例属性
实例属性通过对象进行修改。例如,在以上实例中插入修改实例的代码,具体如下:
class Car:
def drive(self):
self.wheels=4
car=Car()
print(car.drive())
car.wheels=3
print(car.wheels)
(3)动态添加实例属性
Python支持在类的外部使用对象动态地添加实例属性。例如,在以上实例的末尾动态添加实例属性color,增加的代码如下:
class Car:
def drive(self):
self.wheels=4
car=Car()
print(car.drive())
car.color="红色"
print(car.wheels)
print(car.color)
Python中的方法按定义方式和用途可以分为3类:实例方法、类方法和静态方法。
(1)实例方法
实例方法形似函数,但它定义在类内部、以self为第一个形参。如drive()就是一个实例方法。实例方法中的self代表对象本身,它会在实例方法被调用时自动接收由系统传递的调用该方法的对象。
实例方法只能通过对象调用。例如,定义一个包含实例方法drive()的类Car,创建Car类的对象,分别通过对象和类调用实例方法,代码如下:
class Car:
def drive(self):
print("我是实例方法")
car=Car()
car.drive()
Car.drive()
(2)类方法
类方法定义在类内部、使用装饰器@classmethod修饰方法。类方法的语法格式如下所示:
@classmethod
def 类方法名(cls):
方法体
类方法中参数列表的第1个参数为cls,代表类本身,它会在类方法被调用时自动接收由系统传递的调用该类方法的类。
例如,定义一个包含类方法stop()的Car类,代码如下:
class Car:
@classmethod
def stop(cls):
print("我是类方法")
def drive(self):
print("我是实例方法")
car=Car()
car.stop()
car.drive()
Car.stop()
Car.drive()
类方法中可以使用cls访问和修改类属性的值。例如,定义一个包含类属性、类方法的Car类,并在类方法中用cls访问和修改类的属性,然后创建Car类的对象car,对象car调用类方法。代码如下:
class Car:
wheels=3
@classmethod
def stop(cls):
print(cls.wheels)
cls.wheels=4
print(cls.wheels)
car=Car()
car.stop()
(3)静态方法
静态方法是定义在类内部、使用装饰器@staticmethod修饰的方法。静态方法的语法格式如下所示:
@staticmethod
def 静态方法名():
方法体
与实例方法和类方法相比,静态方法没有任何默认参数,它使用于与类无关的操作,或者无须使用类成员的操作,常见于一些工具类中。
例如,定义一个包含静态方法的Car类,代码如下:
class Car:
@staticmethod
def test():
print("我是静态方法")
car=Car()
car.test()
Car.test()
静态方法可以通过类和对象调用
静态方法内部不能直接访问属性或方法,但可以使用类名访问类属性或调用类方法,实例代码如下:
class Car:
wheels=3
@staticmethod
def test():
print("我是静态方法")
#print(wheels)
print(Car.wheels)
car=Car()
car.test()