面向对象知识点1
面对对象编程的特点
继承
在 OOP 程序设计中,当我们定义一个 class 的时候,可以从某个现有的class 继承,新的 class 称为子类(Subclass),而被继承的 class 称为基类、父类或超类(Base class、Super class)。Python当中,父类,子类(派生类),父类和子类只有在继承时才会产生。
继承的优点就是子类可以轻而易举获得父类的所有属性,即减少代码的重复。
#以Animal为父类,People为Animal的子类
class Animal():
def __init__(self, height, weight):
self.height = height
self.weight = weight
class People(Animal):
pass
wq = People(170,140)
print(wq.height,wq.weight) #170 140
#继承后,子类的属性查找先从子类的对象属性中找—子类的函数方法—父类—父类的父类
class Foo:
def f1(self):
print('Foo.f1')
def f2(self): # self = b
print('Foo.f2')
self.f1() # b.f1()
class Bar(Foo):
def f1(self):
print('Bar.f1')
b = Bar()
print(b.__dict__) # {}
b.f2() # Foo.f2
# Bar.f1
类的派生
其实就是子类在继承父类所有的属性和函数方法时,自己拥有的独特的属性和方法,派生就是如何绑定这些独特的属性和函数方法。
#第一种方法:已经脱离了继承的本质,无需继承即可以获得父类的属性和函数方法
class Animal():
def __init__(self, height, weight):
self.height = height
self.weight = weight
class People:
def __init__(self.name,age,height,weight):
Animal.__init__(self,height,weight)
self.name = name
self.age = age
wq = People('wnagqiang,25,175,130')
#第二种方法:必须通过继承父类
class Animal():
def __init__(self, height, weight):
self.height = height
self.weight = weight
class People(Animal):
def __init__(self.name,age,height,weight):
super().__init__(height,weight) #其实是对第一种方法的数据封装
#super(People,self).__init__(height,weight) #python2中的写法
self.name = name
self.age = age
wq = People('wnagqiang,25,175,130')
print(wq.__dict__) #可以通过报错获知属性个数
派生的和关键问题就是弄清楚对象属性的个数以及属性的查找
类的组合
#简单的选课系统
class People:
def __init__(self,name,gender):
self.name = name
self.gender = gender
class Student(People):
def __init__(self,name,id,gender):
super().__init__(name,gender)
self.id = id
def choose_course(self,course):
**self.course = course**
#即通过类的函数对象(引用、返回值,参数)达到类的组合效果
return '%s选课%s成功'%(self.name,course.name)
class Teacher(People):
def __init__(self,name,level,gender):
super().__init__(name,gender)
self.level = level
def scored(self,student,course,score):
return '%s老师给%s学生%s课程打分:%s'%(self.name,student.name,course.name,score)
class Course:
def __init__(self,name,price):
self.name = name
self.price = price
class Admin(People):
def create_course(self,name,price):
course = Course(name,price)
print('管理员%s创建课程%s'%(self.name,name))
return course
#学生
s1 = Student('wangqiang','123','male')
s2 = Student('liujin','124','female')
#老师
t1 = Teacher('nick','0','female')
#管理员
a1 = Admin('sb','eunuch')
#业务逻辑
#1.创建课程
course1 = a1.create_course('python',20000) #管理员sb创建课程python
course2 = a1.create_course('linux',18000) #管理员sb创建课程linux
#2.学生选择课程
print(s1.choose_course(course1))
print(s2.choose_course(course2))
#3.老师打分
print(t1.scored(s1,course1,99)) #nick老师给wangqiang学生python课程打分:99
菱形继承问题
在python3当中会默认继承object类,新式类:只要继承了object类的就是新式类,python3当中所有的类都是新式类。
在python2当中不会默认继承object类,必须得自己手动添加,经典类:没有继承object类的就是经典类, 只有python2当中有经典类。
当继承为菱形继承的时候:在新式类中:当遇到菱形继承时,会以广度优先查找
在经典类中:当遇到菱形继承时,会以深度优先查找
类的多态与多态性
当子类和父类都存在相同的 run()方法时,我们说,子类的 run()覆盖了父类的 run(),在代码运行的时候,总是会调用子类的 run()。这样,我们就获得了继承的另一个好处:多态。
#鸭子类型:子类和父类中都有相同的函数名,当定义一个类的调用函数时,只需要传入类名即可,无需实例
class People:
def sleep(self):
print('p is sleeping!')
class Animal:
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!')
#调用类的定义函数
def run_twice(self):
self.run()
#只需要传入类名()即可调用类中的函数方法
run_twice(Animal()) #animal is running!
run_twice(Dog()) #dog is running!
run_twice(Cat()) #cat is running!