Python进阶(十六)----面向对象之~封装,多态,鸭子模型,super原理(单继承原理,多继承原理)
一丶封装 , 多态
封装:
将一些东西封装到一个地方,你还可以取出来(把一些内容装到某个容器内,用到这些内容还能取出来)
类设置静态属性, 设置一些方法 或者 对象, 对象可以在其对象封装一些属性
多态:
python默认支持多态, 多态指的是一种事务具有多种形态
多态的优点:
1.多态可以增加代码的灵活度;
2.以继承和重写父类方法为前提;
3.是调用方法的技巧,不会影响到类的内部设计
个人理解: 接口(存放功能相类似的函数)重用,一种接口多种实现(通过接口调用相对应的函数)
#### 例1:
#序列类型有多种形态:字符串,列表,元组,但他们直接没有直接的继承关系
#str,list,tuple都是序列类型
s=str('hello')
l=list([1,2,3])
t=tuple((4,5,6))
#我们可以在不考虑三者类型的前提下使用s,l,t
s.__len__() # 三者的序列类型 都有__len_()方法,
l.__len__()
t.__len__()
len(s) # len函数就具有多种形态
len(l)
len(t)
# 解释: len函数就是一种事务, 元组,列表,字符就是多种形态.因为它们三者都含有__len__()函数
#### 例2:
import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
@abc.abstractmethod
def talk(self):
pass
class People(Animal): #动物的形态之一:人
def talk(self):
print('say hello')
class Dog(Animal): #动物的形态之二:狗
def talk(self):
print('say wangwang')
class Pig(Animal): #动物的形态之三:猪
def talk(self):
print('say aoao')
peo=People()
dog=Dog()
pig=Pig()
#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()
#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
obj.talk()
鸭子模型:是动态类型的一种风格
定义:
当看到一只鸟走起来像鸭子,游泳起来像鸭子,叫起来也像鸭子,那么这只鸟就可以被称为鸭子.
概念:
在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为鸭的对象,并调用它的走和叫方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的走和叫方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的走和叫方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。鸭子类型通常得益于不测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。从静态类型语言转向动态类型语言的用户通常试图添加一些静态的(在运行之前的)类型检查,从而影响了鸭子类型的益处和可伸缩性,并约束了语言的动态特性。(摘自CSDN juunny,仅供参考)
class A:
def login(self):
pass
def register(self):
pass
class B:
def login(self):
pass
def register(self):
pass
# A,B两个类,没有任何关系,独立两个,但是里面的功能相似,所以python一般会将类似于A,B两个类
# 里面的相似的功能让其命名相同.
# A,B虽然无关系,但是很默契的制定了一个规范.让你使用起来更方便.
## 个人理解:
#你可以定义一个公共的接口, 简化代码 .牛逼人都这么干
def func(obj):
obj.register()
obj.login()
一篇详细的多态文章
二丶类的约束
归一化设计:
统一接口
### pay函数就作为 统一的接口 不论用哪个平台调用都是使用pay函数
class QQ(Payment):
def pay(self,money):
print(f'支付了 {money}')
class Ali(Payment):
def pay(self,money):
print(f'支付了 {money}')
class WeChat(Payment):
def fuqian(self,money):
print(f'支付了 {money}')
# 定义接口函数
def pay(obj,money):
obj.pay(money)
q=QQ() # 实例化对象
a=Ali()
w=WeChat()
pay(q,200) # 调用接口 实现功能
pay(a,100)
pay(w,1200)
父类建立一种约束
### 父类的约束不是强制性的,不重写父类的 pay函数 也可以调用子类本身的函数,完成支付功能
class Payment:
def pay(self,money):
raise Exception('子类必须继承父类pay方法') # 当子类执行接口函数时,调用函数名与父类不一致,父类pay函数主动抛出一个异常
class QQ(Payment):
def pay(self,money):
print(f'支付了 {money}')
class Ali(Payment):
def pay(self,money):
print(f'支付了 {money}')
class WeChat(Payment):
def fuqian(self,money):
print(f'支付了 {money}')
# 定义接口
def pay(obj,money):
obj.pay(money)
q=QQ() # 实例化对象
a=Ali()
w=WeChat()
pay(q,200)
pay(a,100)
pay(w,1200) # 由于 子类没有重写父类的pay方法, 父类会主动抛出一个异常
模拟抽象类(指定一种规范)的概念,建立一种约束.
### 强制性约束, 必须重写父类的方法
from abc import abstractmethod, ABCMeta # 导入抽象类 和 抽象元类
class Payment(metaclass=ABCMeta): # 定义这个类是一个抽象类
@abstractmethod # 给父类的 pay 函数添加抽象方法装饰器. 当子类没有重写父类方法,实例化对象时,就会报错
def pay(self, money):
pass
class QQ(Payment):
def pay(self, money):
print(f'支付了 {money}')
class Ali(Payment):
def pay(self, money):
print(f'支付了 {money}')
class WeChat(Payment):
def fuqian(self, money):
print(f'支付了 {money}')
# 重写父类的pay函数,就不会报错. 不重写就会报错
def pay(self, money):
pass
# 定义接口
def pay(obj, money):
obj.pay(money)
q=QQ()
a=Ali()
w=WeChat() # 1. 实例化对象时, 就会报错. 必须重写父类的pay函数 ,
pay(q,200)
pay(a,100)
pay(w,1200)
# 由于抽象方法引自与Java的抽象类. so 原理相同
### 抽象类 不能被实例化 ,只能被继承
aa=Payment()
# TypeError: Can't instantiate abstract class Payment with abstract methods pay
三丶super的深入理解
### super() 并不是 执行父类的方法
# 单继承: super() 肯定执行父类的方法
# 多继承: super(S,self)严格按照self(就是当前对象) 从属于类的mro的执行顺序,执行 S类的下一位
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super(Foo,self).f1()
print('in Foo') # 2 按照继承顺序来执行,主动执行当前类的下一个类(按照继承顺序执行) , 执行Bar类
class Bar(A):
def f1(self):
print('in Bar') # 1 按照继承顺序来执行, 执行当前类的下一个类(按照继承顺序执行),已经定位到当前的Bar中的f1函数,就不再向上寻找.
class Info(Foo,Bar):
def f1(self):
super(Info,self).f1() # 从Info当前类开始 ,执行当前类的下一个类(按照继承顺序执行), 执行Foo类, 不写是默认从Info当前类super(Info,self).f1()=super().f1()
print('in Info f1') # 按照继承顺序来执行完毕后, 再执行Info
obj = Info()
print(Info.mro()) # obj对象的 继承顺序[Info, Foo, Bar, A]
obj.f1()
# 结果: in Bar, in Foo , in Info f1
####多继承 , super指定继承哪个类,就从这个类的下一个类执行
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super().f1()
print('in Foo')
class Bar(A):
def f1(self): # self = obj
print('in Bar')
class Info(Foo,Bar):
def f1(self): # self = obj
super(Foo,self).f1() # 这里指定从Foo类继承. 按照多继承规则,会执行下一个类,也就是Bar
print('in Info f1')
obj = Info()
obj.f1() # obj对象的 继承顺序[Info, Foo, Bar, A]
# 结果 : in Bar, in Info f1