第10章 面向对象编程
面向对象编程(简称OOP)是一种组织程序的方法,提倡仔细设计和代码重用。从本质上说对象是一组数据以及操作这些数据的函数。
前面提及的数字、字符串、列表、字典和函数都是对象。
要创建对象,必须先创建类。类指定了对象将包含哪些数据和函数。OOP的一个重要功能就是继承:创建新类时,可以让它继承既有类的数据和函数。
一、编写类
class Person:
def __init__(self):
self.name=""
self.age=0
上述代码定义了一个名为Person的类,它包含数据name和age,以及一个初始化函数。创建Person类的对象时,将会自动调用初始化函数。在这里,函数被称为方法,方法的第一个参数必须是self。
具体创建Person类对象可直接通过”类名()”方式,创建后访问对象的数据可直接通过”对象名.数据名”:
class Person:
def __init__(self):
self.name=""
self.age=0
p=Person()
p.name="ZhangMing"
print(p.name)
print(p.age)
注:初始化函数的参数self:
(1)调用Person()时没有提供任何参数,但其初始化函数却需要一个self参数,在OOP中,self是一个指向对象本身的变量。
(2)所有类都应该有初始化方法,并且该方法第一个参数须是self,也可依据需要在设计初始化方法时指定其他(第二、第三…)参数。
(3)Python中可以像使用其他数据类型一样使用对象,可以作为函数参数,可以作为列表和字典元素,可以保存到文件中等等。
二、显示对象
class Person:
def __init__(self):
self.name=""
self.age=0
def display(self):
print("Person('%s',%d)"%(self.name,self.age))
p=Person()
p.name="ZhangMing"
p.age=18
p.display()
上述代码通过设计了display()方法显示对象的数据,但Python还提供了一些特殊的方法,比如:
class Person:
def __init__(self):
self.name=""
self.age=0
def display(self):
print("Person('%s',%d)"%(self.name,self.age))
def __str__(self):
return "Person('%s',%d)"%(self.name,self.age)
p=Person()
p.name="ZhangMing"
p.age=18
p.display()
print(p)
另外,还可以定义特殊方法repr,它返回对象的官方表示:
class Person:
def __init__(self):
self.name=""
self.age=0
p=Person()
p.name="ZhangMing"
p.age=18
print(p)
上述代码打印结果为:
<__main__.Person object at 0x0000000002B25400>
这即为其原始的“官方”表示,可以添加repr方法:
class Person:
def __init__(self):
self.name=""
self.age=0
def __str__(self):
return "Person('%s',%d)"%(self.name,self.age)
def __repr__(self):
return str(self)
创建自己的类时,编写函数—str—和repr总是值得的。其对于显示对象内容很有用。
三、灵活的初始化
在类的初始化方法中也可以直接设定属性参数,可以更方便的创建对象并指定其属性数据:
class Person:
def __init__(self,name="",age=0):
self.name=name
self.age=age
def display(self):
print("Person('%s',%d)"%(self.name,self.age))
def __str__(self):
return "Person('%s',%d)"%(self.name,self.age)
def __repr__(self):
return str(self)
p=Person("ZhangMin",18)
print(p)
四、设置函数和获取函数
class Person:
def __init__(self,name="",age=0):
self.name=name
self.age=age
def display(self):
print("Person('%s',%d)"%(self.name,self.age))
def set_age(self,age):
if 0<age<200:
self.age=age
def __str__(self):
return "Person('%s',%d)"%(self.name,self.age)
def __repr__(self):
return str(self)
p=Person("ZhangMin",18)
p.set_age(36)
print(p)
如上代码,可以通过设置了set_age()方法对于合适范围内的取值才有效。
五、继承
先设计一个玩家的类:
class Player:
def __init__(self,name):
self._name=name
self._score=0
def reset_score(self):
self._score=0
def incr_score(self):
self._score=self._score+1
def get_name(self):
return self._name
def __str__(self):
return "name='%s',score=%s" %(self._name,self._score)
def __repr__(self):
return "Player(%s)" % str(self)
p=Player("Moe")
print(p)
p.incr_score()
print(p)
p.reset_score()
print(p)
假设有两种玩家,都符合上述Player的描述,其中有一种是人类玩家,就可以使其继承Player类:
class Player:
def __init__(self,name):
self._name=name
self._score=0
def reset_score(self):
self._score=0
def incr_score(self):
self._score=self._score+1
def get_name(self):
return self._name
def __str__(self):
return "name='%s',score=%s" %(self._name,self._score)
def __repr__(self):
return "Player(%s)" % str(self)
class Human(Player):
pass
p=Player("Moe")
print(p)
p.incr_score()
print(p)
p.reset_score()
print(p)
h=Human("Jack")
print(h)
h.incr_score()
print(h)
h.reset_score()
print(h)
>>> p
Player(name='Moe',score=0)
>>> h
Player(name='Jack',score=0)
对于上述代码,Human类的字符串表示为Player,这里可以给Human重新定义repr方法,这就称为重写方法:
class Player:
def __init__(self,name):
self._name=name
self._score=0
def reset_score(self):
self._score=0
def incr_score(self):
self._score=self._score+1
def get_name(self):
return self._name
def __str__(self):
return "name='%s',score=%s" %(self._name,self._score)
def __repr__(self):
return "Player(%s)" % str(self)
class Human(Player):
def __repr__(self):
return "Human(%s)"% str(self)
h=Human("Jack")
>>> h
Human(name='Jack',score=0)
在上面这个例子中,Player为基类,常被称为父类;Human类则为派生类,被称为子类。