python之类的详解(中)—封装、继承、多态,C3算法的介绍

专题11:python之类的详解(上)—面向对象、类的定义和使用、相关概念
专题12:python之类的详解(中)—封装、继承、多态,C3算法的介绍
专题13:python之类的详解(下)—实例方法、静态方法和类方法详解(包含区别和用法)

封装

使用封装能隐藏对象实现细节,使代码更易维护,
同时因为不能直接调用、修改对象内部的私有信息,在一定程度上保证了系统安全性。
类通过将函数和变量封装在内部,实现了比函数更高一级的封装。

class Person(object):
	def __init__(self):
    	self.__name='a'
    	self.age = None
	@property            # 使用@property将一个方法name变成属性,可以直接.name访问
    def name(self):      # 封装self.__name属性
    	return self.__name                   
 
p1=Person()
p1.name       
p1.age 

继承

单继承

以下的示例代码 主要包含的知识点:继承的定义 构造函数的继承 子类属性的定义 子类对父类方法的重写

class People():     # 定义一个父类

	def __init__(self,name,age,gender):   # 父类属性
		self.name = name
        self.age = age
        self.gender = gender

    def speak(self):   # 父类方法
        print("%s 说: 我 %d 岁。" % (self.name, self.age))

# 1.经典类的写法: 父类名称.__init__(self,参数1,参数2,...)
# 2.新式类的写法:super(子类,self).__init__(参数1,参数2,....)


class Student(People):
	
	def __init__(self,name,age,gender,no):
		super(Student,self).__init__(name,age,gender) # People.__init__(self, name,age,gender)  #继承父类的构造方法
		self.no = no  # 子类的属性
	
	def score(self): # 子类的方法
		return "60分,及格了"

	 def speak(self):   # 子类对父类方法的重写
        print("我是学生")


class Teacher(People):
	pass
C3算法

在介绍多继承之前需要先了解一下python中的继承算法—C3算法

判断mro要先确定一个线性序列,然后查找路径由序列中类的顺序决定。所以C3算法就是生成一个线性序列。
通用公式
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )(其中Child继承自Base1, Base2)

如果继承至一个基类: class B(A) 这时B的mro序列为[B,A]
如果继承至多个基类: class B(A1,A2,A3 …)
这时B的mro序列 mro(B) = [B] + merge(mro(A1), mro(A2), mro(A3) …, [A1,A2,A3])
merge操作就是C3算法的核心。
遍历执行merge操作的序列,如果一个序列的第一个元素,是其他序列中的第一个元素,或不在其他序列出现,则从所有执行merge操作序列中删除这个元素,合并到当前的mro中。
merge操作后的序列,继续执行merge操作,直到merge操作的序列为空。
如果merge操作的序列无法为空,则说明不合法。

这里简单介绍一下,如果有详细了解的可以看看源码,或者推荐看一下这篇文章C3 线性化算法与 MRO

源码

#-*- encoding:GBK -*-#  
def mro_C3(*cls):  
	if len(cls)==1:  
	    if not cls[0].__bases__:  
	        return  cls  
	    else:  
	        return cls+ mro_C3(*cls[0].__bases__)  
	else:  
	    seqs = [list(mro_C3(C)) for C in cls ] +[list(cls)]  
	    res = []  
	    while True:  
	      non_empty = list(filter(None, seqs))  
	      if not non_empty:  
	          return tuple(res)  
	      for seq in non_empty:  
	          candidate = seq[0]  
	          not_head = [s for s in non_empty if candidate in s[1:]]  
	          if not_head:  
	              candidate = None  
	          else:  
	              break  
	      if not candidate:  
	          raise TypeError("inconsistent hierarchy, no C3 MRO is possible")  
	      res.append(candidate)  
	      for seq in non_empty:  
	          if seq[0] == candidate:  
	              del seq[0]
多继承

多重继承的目的是从两种继承树中分别选择并继承出子类,以便组合功能使用。

事例1
class D:
    pass

class C(D):
    pass

class B(C): 
    def show(self):
        print("i am B")
    pass

class G:
    pass

class F(G):
    pass

class E(F): 
    def show(self):
        print("i am E")
    pass

class A(B, E):
    pass

a = A()
a.show()

上面的这段代码输出的结果是?i am B
其实呢,就是下面的这种继承关系
在这里插入图片描述
如果B类中没有show() 而是在 D类呢?执行结果是 “i am D”,

左边具有深度优先权,搜索的顺序如下
在这里插入图片描述

事例2

在这里插入图片描述
还有一种继承情况就是,假设D类G类 都继承了 H类 当只有B类E类show方法的时候,无疑和上面的例子一样,找到B就不找了,直接打印"i am B"。但如果是只有H和Eshow方法呢?

class H:
    def show(self):
        print("i am H")
    pass

class D(H):
    pass

class C(D):
    pass

class B(C):
    pass

class G(H):
    pass

class F(G):
    pass

class E(F): 
    def show(self):
        print("i am E")
    pass

class A(B, E):
    pass

a = A()
a.show()

你可能会以为会打印 “i am H”,但是,打印的却是 “i am E”!为什么?因为在这种情况下,Python的搜索路径是这样的:
在这里插入图片描述

到这里呢,python中的继承就讲的差不多了,归根结底就这些内容,不是特写的复杂,重要的是理解继承的原理,学会使用一些方法。多么复杂的多继承,基本是上边划分的两种情况,其实C3算法不需要会,想学习的可以了解一下
最后通过一张图片分析一下C3算法
在这里插入图片描述

继承部分参考文章:点击查看

多态

直接先看一段代码,帮助你理解多态

class Animal():
	def eat(self):
		return "吃食物"
		
class Dog(Animal):
	def eat(self):
		return "我吃骨头"
		
class Cat(Animal):
	def eat(self):
		return "我吃鱼"
	
class Pig(Animal):
	def eat(self):
		return "我吃蔬菜"

# 这个函数接收一个animal参数,并调用它的kind方法
def eat_food(animal):
    animal.eat()
    
d = Dog()
c = Cat()
p = Pig()
eat_food(d)
eat_food(c)
eat_food(p)

狗、猫、猪都继承了动物类,并各自重写了 eat方法。eat_food函数接收实例化对象为参数,调用它的 eat 方法。可以看出,无论我们给animal传递的是狗、猫还是猪,调用相应的方法,打印对应的信息。这就是多态。

由于python是一门动态类型的语言,在调用实例方法不检查类型,只要方法存在参数正确,就可以直接调用。这就是python中的多态,没有严格意义上的继承体系,我们称之为 鸭子类型——一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。


最后还想说一下这个super,文末突然想起来了
super的用途呢,主要两种情况

  • 1.对父类构造函数的重写
  • 2.在子类中调用父类的方法
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值