面向对象程序设计具有许多优点:
1、开发时间短,效率高,可靠性高,所开发的程序更强壮。由于面向对象编程的可重用性,可以在应用程序中大量采用成熟的类库,从而缩短了开发时间。
2、应用程序更易于维护、更新和升级。继承和封装使得应用程序的修改带来的影响更加局部化。
1.面向对象的三大特征:封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)
.继承: 继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。这也体现了大自然中一般与特殊的关系。继承性很好的解决了软件的可重用性问题。比如说,所有的Windows应用程序都有一个窗口,它们可以看作都是从一个窗口类派生出来的。但是有的应用程序用于文字处理,有的应用程序用于绘图,这是由于派生出了不同的子类,各个子类添加了不同的特性。
- 最大的好处是子类获得父类全部功能,实现代码重用
class Animal:
def eat(self):
print('%s爱吃' %(self.name))
def drink(self):
print('%s要喝水' %(self.name))
class Cat(Animal):
def __init__(self,name):
self.name = name
def sleep(self):
print('%s爱睡觉' %(self.name))
class Dog(Animal):
def __init__(self,name):
self.name = name
def dance(self):
print('%s爱跳' %(self.name))
cat1 = Cat('tom')
cat1.sleep()
cat1.drink()
cat1.eat()
dog1 = Dog('Jeck')
dog1.drink()
dog1.dance()
运行:
tom要喝水
tom爱吃
Jeck要喝水
Jeck爱跳
Process finished with exit code 0
class Animal(): #定义动物类
def run(self):
print('running~~')
def call(self):
print('hahahah') # 动物类中存在两个方法
class Cat(Animal): # 定义猫类,继承动物类
pass
tom = Cat() # 常见一个猫类实例
tom.run() # 该实例可以直接调用动物类的方法
#输出结果:
running~~
可以在子类中添加自己特定功能的一些方法
class Animal():
def run(self):
print('running~~')
def call(self):
print('hahahah')
class Cat(Animal):
def eat(self):
print('爱吃鱼')
tom = Cat()
tom.run() # 调用父类的方法
tom.eat() # 使用自己类的方法
#输出结果:
running~~
爱吃鱼
当父类方法的实现不能满虚子类的需求的时候可以对方法进行重写,我们说,子类的方法覆盖了父类的方法,在代码运行的时候,总是会调用子类的该方法。
class Animal():
def run(self):
print('running~~') #父类中存在run方法
def call(self):
print('hahahah')
class Cat(Animal):
def run(self):
print('跑得快') # 子类中也存在run方法
def eat(self):
print('爱吃鱼')
tom = Cat()
tom.run() # 当实例调用run方法的时候,总是调用的子类中的程序
#运行结果:
跑得快
可以对父类方法进行扩展。保留父类方法的内容,在其基础上增加新的内容。只需要子子类中定义和父类中相同的方法,并且在该方法中写入super().call()(父类.方法(self) python2.x通过个该实现),然后添加需要扩展的内容即可。
在这里插入代码片
class Animal():
def run(self):
print(‘running~~’)
def call(self):
print(‘hahahah’)
class Cat(Animal):
def run(self):
super().run() # 继承父类给方法的内容,同时添加扩展的内容
print(‘跑得快’)
def eat(self):
print(‘爱吃鱼’)
tom = Cat()
tom.run()
#输出结果:
running~~
跑得快
当父类中使用了初始化方法,在子类中也想使用初始化方法的时候,需要使用在子类初始化方法中使用super().init(),表示对父类初始化方法的继承扩展,如若没有,会出现冲突报错。
class Animal():
def __init__(self,name):
self.name = name
def run(self):
print('running~~')
def call(self):
print('hahahah')
class Cat(Animal):
def __init__(self,color,name):
super().__init__(name) #在子类中必须使用该语句,表示继承父类中的属性。
self.color = color
def run(self):
super().run()
print('跑得快')
def eat(self):
print('爱吃鱼')
tom = Cat('tom','red')
print(tom.name)
print(tom.color)
#输出结果:
red
tom
当子类继承子多个父类的时候,并且多个父类中存在相同的方法,这时候该子类的实例取调用这个方法的时候,就会出现那个被继承的父类写在前面,就使用哪一个父类的方法。建议在定义方法的时候,尽量不要使用相同的名称
class A: #定义A 类
def lala(self):
print('lala')
def toto(self):
print('toto') # 其中由来两个方法
class B: # 定义B类
def lala(self):
print('LALA')
def toto(self):
print('TOTO') # 其中由两个方法,并且方法名称和A中方法名称一致
class C(A,B): #定义类C 继承A,B 两个类
pass
class D(B,A): # 定义类D 继承B,A 两个类
pass
c = C()
d = D()
c.lala()
d.lala()
c.toto()
d.toto() # 当继承父类的顺序不同的时候,导致调用的方法是不同的内容,默认调用位置靠前的父类方法
#输出结果:
lala
LALA
toto
TOTO
.封装:
封装是面向对象的特征之一,是对象和类概念的主要特性。封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。一旦定义了一个对象的特性,则有必要决定这些特性的可见性,即哪些特性对外部世界是可见的,哪些特性用于表示内部状态。在这个阶段定义对象的接口。通常,应禁止直接访问一个对象的实际表示,而应通过操作接口访问对象,这称为信息隐藏。事实上,信息隐藏是用户对封装性的认识,封装则为信息隐藏提供支持。封装保证了模块具有较好的独立性,使得程序维护修改较为容易。对应用程序的修改仅限于类的内部,因而可以将应用程序修改带来的影响减少到最低限度。
class Person: ##定义一个类
def __init__(self,name,age,gender): #类属性有姓名、年龄和性别
self.name = name
self.age = age
self.gender = gender
def eat(self):
print("%s今年%s岁%s,喜欢布娃娃" %(self.name,self.age,self.gender)) #构造类方法将其封装到对象中,通过对象调取
def study(self):
print("%s今年%s岁%s,爱学习" % (self.name, self.age, self.gender))
def paint(self):
print("%s今年%s岁%s,爱画画" % (self.name, self.age, self.gender))
name = Person("lily",10,"女") #创建的对象
name.eat()
name.study()
name.paint()
1 示例说明:满足以下需求
需求
1.小明体重75.0公斤
2.小明每次跑步都会减肥0.5公斤
3.小明每次吃东西体重都会增加1公斤
需求
1.小明和小美都爱跑步
2.小美体重45.0公斤
2.每次跑步都会减肥0.5公斤
3.每次吃东西体重都会增加1公斤
class Person:
def __init__(self,name,weight):
self.name = name
self.weight = weight
def __str__(self):
return 'this is %s ,my weight is %.2f ' %(self.name,self.weight)
def eat(self):
print('%s 吃饭' %self.name)
self.weight += 1
def run(self):
print('%s 跑步' %self.name)
self.weight -= 0.5
#将属性和方法都封装在一个类中
xiaoming = Person('xiaoming',70) # 使用列创建对象
xiaoming.eat() # 使用对象调用方法
xiaoming.run()
print(xiaoming)
xiaohua = Person('xiaohua',45)
xiaohua.eat()
xiaohua.run()
print(xiaohua)
#输出结果:
xiaoming 吃饭
xiaoming 跑步
this is xiaoming ,my weight is 70.50
xiaohua 吃饭
xiaohua 跑步
this is xiaohua ,my weight is 45.50
2 根据学生的成绩得到成绩的等级
class Student:
def __init__(self,name,score):
#初始化方法,当使用类创建实例的时候都会调该方法
self.name = name
self.score = score
def get_grade(self):
#对数据封装
if self.score > 90:
print('A')
elif self.score >80:
print('B')
else:
print('C')
toto = Student('toto',95) # 创建对象
toto.get_grade() # 直接使用对象调用方法,得到结果
#输出结果:
A
一个对象的属性 可以是另一个对象创建的类
需求:
1.房子有户型,总面积和家具名称列表
新房子是没有家具的
2.家具有名字和占地面积,其中
床:5
桌子:4
椅子:6
3.将以上三件家具添加到房子中
4.打印房子的时候,要求输出:户型 总面积 剩余面积 家具名称列表
class Furniture: # 限定义家具类
def __init__(self,name,area):
self.name = name
self.area = area
def __str__(self):
return 'this is %s, %d square '
#使用类创建好对象之后,该对象可以作为参数用于其他函数调用。
class House: #在定义房子类
def __init__(self,type,squa):
self.fu_list = []
self.type = type
self.leftsqua = self.allsqua = squa
def __str__(self):
return ' 户型是: %s\n 总面积是: %.2f\n 剩余面积: %.2f\n 家具列表:%s' \
%(self.type,self.allsqua,self.leftsqua,self.fu_list)
def add_furn(self,item): # 在房子类的方法中使用的参数是家具类的一个实例
if item.area<self.allsqua:
self.fu_list.append(item.name)
self.leftsqua -=item.area
else:
return
bed = Furniture('bed',5)
desk = Furniture('desk',4)
chair = Furniture('cabinet',6) # 先实例化 家具
house1 = House('三室',120) # 在实例化房子
house1.add_furn(bed) # 再使用房子对象的方法,传入的参赛是家具实例
house1.add_furn(desk)
house1.add_furn(chair)
print(house1)
#输出结果:
户型是: 三室
总面积是: 120.00
剩余面积: 105.00
家具列表:['bed', 'desk', 'cabinet']
1.士兵瑞恩有一把AK47
2.士兵可以开火(士兵开火扣动的是扳机)
3.枪 能够 发射子弹(把子弹发射出去)
4.枪 能够 装填子弹 --增加子弹的数量
class Gun: # 定义枪类
def __init__(self,name):
self.name = name
self.count = 3 # 属性:枪名称以及子弹数量
def add_bullet(self): # 方法:添加子弹,将子弹数充值3
self.count = 3
def launch_bullet(self): # 发射子弹
if self.count <= 0:
self.add_bullet() #如果没有子弹,先进行添加子弹
self.count -= 1 # 然后子弹减少一个
print('%s 已经成功发射子弹 剩余子弹%d' %(self.name,self.count))
class Solair: # 定义士兵类
def __init__(self,name):
self.name = name # 设置属性 :name
def shoot(self,gun): # 定义方法:直接调用枪对象的方法
gun.launch_bullet()
AK47 = Gun('AK47') # 实例化一个枪对象
ryan = Solair('Ryan') #实例化一个士兵对象
ryan.shoot(AK47) # 士兵对象调用开火方法
ryan.shoot(AK47)
ryan.shoot(AK47)
ryan.shoot(AK47)
#结果:
AK47 已经成功发射子弹 剩余子弹2
AK47 已经成功发射子弹 剩余子弹1
AK47 已经成功发射子弹 剩余子弹0
AK47 已经成功发射子弹 剩余子弹2
多态性:
多态性是指允许不同类的对象对同一消息作出响应。比如同样的加法,把两个时间加在一起和把两个整数加在一起肯定完全不同。又比如,同样的选择编辑-粘贴操作,在字处理程序和绘图程序中有不同的效果。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。
以封装和继承为前提,存在一个函数,需要一个参数,不用对函数进行修改当参数是不同的对象的时候输出的结果不同,
就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。
不同的子类对象调用相同的方法,产生不同的执行结果
首先要对数据类型再作一点说明。当我们定义一个class的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
pass
class Cat(Animal):
pass
a = list()
b = Animal()
c = Dog()
d = Cat()
print(isinstance(a,list))
print(isinstance(b,Animal))
print(isinstance(c,Dog))
print(isinstance(d,Cat))
#输出结果:
True
True
True
True
同时子类实例化出来的对象,不仅是子类类型,同时还是父类类型。在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。例如Animal是Dog的父类,使用Dog实例化一个实例,该实例既是Dog类型,也是Animal类型。
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
pass
b = Animal()
c = Dog()
print(isinstance(b,Animal))
print(isinstance(c,Dog))
print(isinstance(c,Animal))
#输出结果:
True
True
True
首先存在三个类:Animal、Dog、Cat;Dog、Cat 都继承自Animal类,并且都存在run方法。
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running')
class Cat(Animal):
def run(self):
print('Cat is running')
理解多态的好处,我们还需要再编写一个函数,这个函数接受一个Animal类型的变量:
def run_twice(animal):
animal.run()
animal.run()
当我们传入Animal类的实例时,run_twice()就打印出:
def run_twice(animal):
animal.run()
animal.run()
run_twice(Animal())
#输出结果:
Animal is running...
Animal is running...
由于Dog类的实例以及Cat类的实例都可以是Animal数据类型,同样也可以作为参数传入该函数,当传入Dog类的实例以及Cat类的实例时候,函数的输出:
def run_twice(animal):
animal.run()
animal.run()
run_twice(Dog())
run_twice(Cat())
#输出结果:
Dog is running
Dog is running
Cat is running
Cat is running
现在可以在定义一个以Animal作为父类的子类,并将其实例作为参数,函数run_twice可以正常的运行。
class Tortoise(Animal):
def run(self):
print('Tortoise is running slowly~~~')
run_twice(Tortoise())
#输出结果:
Tortoise is running slowly~~~
Tortoise is running slowly~~~