面向对象,特性之继承

面向对象三大特性之继承

1,什么是继承?

  • 继承指的是一种关系,必须存在两个对象才能产生这种关系

  • 被继承的称为父,继承的一方称为子

  • 在程序中,继承指的是类与类之间的关系

2,为什么要使用继承?

继承可以扩展已存在的代码模块(类)

在程序中,通过继承可以直接使用父类已有的代码

3,怎么使用继承

继承类的语法

class Father:
  pass

class Som(Father):     #子类后面加上括号,写上父类的名称
  pass
在python中,一个字类可以有多个父类,多个父类在括号中用逗号隔开

 

继承父类中对象和方法的语法

class Parent:
  year = 2018
  def coding(self):
      print('coding')
   
class Sub(Parent):
  pass
print(Sub.year)
s1 = Sub()
s1.coding()
4,继承对编程的作用

假设有个学生管理需求:

class Student:
  def __init__(self,name,age,sex):
      self.name = name
      self.age = age
      self.sex = sex
  def study(self):
      print('正在学习中')
  def eat(self):
      print('正在吃饭中')

 

后续又要求添加老师管理需求:

学生的属性和技能也适用于老师,此时可以引用继承,减少代码的冗余
class Teacher(Student):
  pass
t1 = Teacher('alex',30,'man')
t1.eat()
t1.study()

从逻辑上来说,如果学生有打游戏的技能,而老师并没有这个需求,因此继承到了老师并不需要的技能

 

正确姿势: 抽取公共的父类 (抽象)

抽象 : 抽取多个类中相同得部分,形成另一个类

把学生和老师共有的内容抽到另一个类中,学生和老师分别继承这个类,这样就避免了一个类继承到不需要的内容 因此应该先抽象,再继承

 

 

小结:
  • 通过继承,避免了重复代码的编写。

  • 继承的作用是可以直接使用父类已有的代码

  • 通过抽象,避免了一个类继承到不需要的内容

  • 抽象的作用是存储多个子类相同的属性和技能

  • 正确地顺序应该先抽象,再继承

 

 

派生和覆盖

1,派生

class Person:
•  def __init__(self,name,age,sex):
•      self.name = name
•      self.age = age
•      self.sex = sex

•  def sayhi(self):
•      print('hello,')

class Student(Person):                     # 学生属于人类,可以直接继承
•  def __init__(self,number):             # 加上一些学生特有的属性
•      self.number = number

•  def study(self):
•      print('%s正在学习'%self.name)
  • 派生指某个子类继承父类,并且拥有自己独特的属性或技能

  • 该子类称之为派生类

  • 只要子类中出现任何新内容,这就是一个派生类

 

2,覆盖

class A:
  age = 18#age相同
  def f1(self):#f1相同
      print(" A f1" )
  pass

class B(A):
  age1 = 19
  def f1(self):#f1
      self.f1()
      print(" B f1")

b1 = B()
print(b1.age)

b1.f1()

 

小结:
  • 子类出现了与父类重复的名字 称之为覆盖

  • 子类出现了与父类不同的名字 称之为派生

 

 

子类访问父类的方法

方法1 从父类去调
class Person:
  def __init__(self,name,age,sex):
      self.name = name
      self.age = age
      self.sex = sex

  def sayhi(self):
      print('hello,')

class Student(Person):                     # 学生属于人类,可以直接继承
  def __init__(self,name,age,sex,number): # 加上一些学生特有的属性

#self.name = name
#self.age = age
#self.sex = sex           #代码重复

      Person.__init__(self,name,age,sex)   #在子类访问父类的方式1
      self.number = number

      def study(self):
          print('%s正在学习'%self.name)
stu1 = Student('成龙',20,'man',4235)
print(stu1.__dict__)

 

方法2 super()函数
class Person:
  def __init__(self,name,age,sex):
      self.name = name
      self.age = age
      self.sex = sex

  def sayhi(self):
      print('hello,')

class Student(Person):                     # 学生属于人类,可以直接继承
  def __init__(self,name,age,sex,number): # 加上一些学生特有的属性

      super(Student,self).__init__(name,age,sex)     #super()表示特殊的对象
      super().__init__(name,age,sex)#效果一样,这是py3的语法
self.number = number

  def study_1(self):
      super().sayhi()               #访问父类的方法1
      Person.sayhi(self)           #访问父类的方法2
      print('%s正在学习'%self.name)

stu1 = Student('成龙',20,'man',4235)
stu1.study_1()
print(stu1.__dict__)

了解,在python2中,super的用法不同。super(Student,self).init()

super一定用在存在继承关系的子类中

 

 

子类访问父类的顺序

1,存在一个父类的情况
class A:
  age = 10
class B(A):
  age = 11
class C(B):
  age = 12

c1 = C()
c1.age = 13
print(c1.age)
顺序 : 对象 >>> 类 >>> 父类 >>> 父类的父类...

沿着继承关系找,无论是属性还是方法! 如果没有则报错!

 

2,存在多个父类的查找顺序

(1) ,继承的父类,没有父类,按照继承顺序,从左往右依次查找
class A:
  a = 0
  pass
class B:
  a = 1
  pass
class C:
  a = 2
  pass
class D(A,B,C):
  a = 3
  pass
d = D()
d.a = 4
print(d.a)

 

查找顺序为 : A -- B -- C -- D

(2),深度优先,沿着一条线找到底

继承的父类,存在父类,则先把父类找完 ​ 这种查找方式仅仅在非菱形继承(没有共同父类)的情况下

class Q:
  a = 10
class A(Q):
  a = 0
  pass
class W:
  a = 11
class B(W):
  a = 1
  pass
class C:
  a = 2
  pass
class D(A,B,C):
  a = 3
  pass
d = D()
d.a = 4
print(d.a)

 

 

查找顺序为E -- A -- F -- B --同理

3,广度优先,并非绝对的广度优先,而是基于深度的广度优先。

先是深度优先,如果发现有共同父类,则返回。最后再查找共同父类 ​ 该查找顺序是通过C3算法得来

 

 

了解:

可以用 mro(类) 获取 类查找的路径

 

 

 

新式类和经典类

主要针对 python2 和 python3 区分的

所有直接继承或间接继承object的类 都是新式类

object 称之为根类 意思是 所有类 都源自于object类
为什么这么设计?
  1. 例如:创建对象时,需要申请内存空间,创建新的名称空间,将对象的属性放入名称空间, ​ 这一些了复杂的基础操作,都yo由object来完成 ​ 简单地说object提供了一些常用的基础操作

  2. 即所有类都属于新式类(在python3中)

在python3中默认所有类都是新式类

而python2中默认是经典类(不会自动继承Object)

 

class S:
  pass
class Student(S):
  pass

 

bases__用于查看父类

print(Student.__bases__)

显示属性的查找顺序列表,属性查找属性就是按照该列表来查找的

print(Student.mro())

 

mro

查看访问路径

"super访问父类内容时 按照mro列表属性查找"


class S:
  def f1(self):
      print("s f1")

class A(S):
  pass

class B(S):
  def f1(self):
      print("b f1")
  pass

class C(A,B):
  def f2(self):
      print("c f2")
      super().f1()


print(C.mro())
c1 = C()
c1.f2()



组合

1,什么是组合

  • 多个对象放在一起就是组合

  • 一个对象将另一个对象作为自己的属性,就是组合

2,组合的目的

  • 处理数据更有效率,有效降低耦合度和代码的冗余

3,组合的实现

  • 代码1 是通过继承实现代码的精简

  • 但是如果继续添加一些功能,比如学生和老师的手机

  • 手机的属性有品牌,价格,运营商,号码

  • 如果全部都放到代码1 的父类中,看起来非常的臃肿,管理成本非常高,扩展性变得很差

  • 我们可以通过组合实现代码的管理,使代码的可读性和整洁性都得到有效提高

  • 代码2 是添加手机功能后通过继承和组合一起实现.

  • 组合其实我们在用户交互的练习就实现过了

 

代码1,继承
class Person:
  def __init__(self, name, sex, age, number):
      self.name = name
      self.sex = sex
      self.age = age
      self.number = number
       
class Student(Person):
  def __init__(self,name,sex,age,number,game):
      super().__init__(name,sex,age,number)
      self.game = game
  def show_info(self):
      print(self.__dict__)
  def select(self):
      print('%s正在选课'%self.name)
       
class Teacher(Person):
  def __init__(self,name,sex,age,number,teach_class):
      super().__init__(name,sex,age,number)
      self.teach_class = teach_class
  def show_info(self):
      print(self.__dict__)
  def set_score(self):
      print('%s正在为学生打分'%self.name)
s1 = Student('韩信','man',18,51,'王者荣耀')
s1.show_info()
t1 = Teacher('韩信','man',18,51,'王者荣耀')
t1.show_info()

 

代码2 ,组合的形式

 


class Phone:#组合的代码
  def __init__(self,phonenumber,operator,address):
      self.phonenumber = phonenumber
      self.operator = operator
      self.address = address

  def call(self,t):
      print("%s 正在拨号 %s" % (t.name,self.phonenumber))


class Person:#父类
  def __init__(self,name,sex,age):
      self.name = name
      self.sex = sex
      self.age = age
       
class Student(Person):#子类
  def __init__(self,name,sex,age,number):
      super().__init__(name, sex, age)
      self.number = number
  def show_info(self):
      print(self.__dict__)
  def select_cursor(self):
      print("%s 正在选课...." % self.name)
       
class Teacher(Person):#子类
  def __init__(self,name,sex,age,salary,level):
      super().__init__(name,sex,age)
      self.salary = salary
      self.level = level
  def set_score(self):
      print("%s 正在为学生打分..." % self.name)

stu = Student("乔峰","男",38,"007")

p1 = Phone("1999999999","中国小米移动","上海浦东")

stu.q = p1             #这里的q是变量名,相当于把p1赋值给q,通过stu来调用

stu.q.call(stu) #不能直接stu.p1.call()

 

 

 

 

猜你喜欢

转载自www.cnblogs.com/wang-kai-1994/p/10167198.html