目录
1.封装
2.继承
1.概念
2.分类
3.type和object区分
4.继承下的影响
1.资源的继承
2.资源的使用
1.继承的几种形态
2.几种形态应该遵循的标准原则
3.针对于几种标准原则的方案演化
1.python不用版本方案演化
2.概念补充
MRO
深度优先
广度优先
C3算法
3.资源的覆盖
4.资源的累加
方案1(通过父类名调用)
方案2(通过super调用)
3.多态
4.补充:抽象类,抽象方法
1.封装
概念
将一些属性和相关方法封装在一个对象中;
对外隐藏内部具体实现细节
如:电脑主机
内部实现,外界不需要关心;
外界只需要根据“内部提供的接口”去使用就可以
好处
1.使用起来更加方便
因为已经把很多相关的功能,封装成一个整体
类似于像外界提供一个工具箱
针对于不同的场景,使用不同的工具箱就可以
2.保证数据的安全
针对于安全级别高的数据,可以设置成”私有”;
可以控制数据为只读,外界无法修改;
也可以拦截数据的写操作,进行数据校验和过滤
3.利于代码维护
如果后期,功能代码需要维护,则直接修改这个类内部代码即可;
只要保证接口名称不变;外界不需要做任何代码修改
2.继承
1.概念
现实中的“继承”:子女继承父母的“财产资源”
编程中的”继承”:
一个类”拥有”另外一个类的”资源”的方式之一;
“拥有”:并不是资源的复制,变成双份资源,而是 资源的”使用权”
“资源”:指”非私有的”属性和方法
目的:方便资源重用
2.分类
单继承
概念:仅仅继承了一个父类
语法:
class Animal:
pass
class Dog(Animal):
pass
多继承
概念:继承了多个父类
语法:
class Animal:
pass
class xxx:
pass
class Dog(Animal,xxx):
pass
3.type和object区分
type是用于创建类的元类(元类:创建类对象的类);
object是所有类的基类,所有类继承自object。
object是根:所有类都继承自type是创建者:所有类都是
object的实例循环关系:
type继承自
type,而
object又是
object的实例统一模型:这种设计使得Python中的所有东西都是对象,包括类本身
type
class Animal:
pass
class xxx:
pass
class Dog(Animal,xxx):
pass
#查看类 继承了哪些父类
print(Dog.__bases__)#(<class '__main__.Animal'>, <class '__main__.xxx'>)
print(Animal.__bases__)#(<class 'object'>,)
# print(int.__bases__)#(<class 'object'>,)
# print(float.__bases__)#(<class 'object'>,)
# print(bool.__bases__)#(<class 'int'>,) bool类型非0即1
d=Dog()
print(d.__class__)#<class '__main__.Dog'>
print(Dog.__class__)#<class 'type'>
print(type.__class__)#<class 'type'>
print(object.__class__)#<class 'type'>

4.继承下的影响
1.资源的继承
明确:
在Python中,继承是指,资源的使用权,
所以,测试某个资源能否被继承,其实就是测试在子类当中,能不能访问到父类当中的这个资源。
结论:
除了私有的属性和私有的方法,其他的基本都能继承,
包括:公有属性/方法,受保护的属性/方法,内置方法。
# 属性和方法
# 设置不同权限的属性和方法,继承当中,进行测试
# 在子类当中,能否访问到这些资源
class Animal:
a=1
_b=2
__c=3
def t1(self):
print("t1")
def _t2(self):
print("t2")
def __t3(self):
print("t3")
def __init__(self):
print("init,Animal")
class Person(Animal):
def test(self):
print(id(self.a))#1896067956976
print(self.a)
print(self._b)
# print(self.__c) #报错
self.t1()
self._t2()
# self.__t3() #报错
self.__init__()
p=Person()
p.test()
#id(self.a)和id(Animal.a)一致,说明是同一个属性,子类只是拥有使用权(读取),而不是复制一份
print(id(Animal.a))#1896067956976
class B:
age=10
class A(B):
pass
print(A.age)#10
# 给A新增了一个age属性,而不是修改了父类B的age
A.age=9
print(B.age)#10
#{'__module__': '__main__', '__doc__': None, 'age': 9}
#{'__module__': '__main__', 'age': 10, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None}
print(A.__dict__)
print(B.__dict__)
2.资源的使用
1.继承的几种形态
单继承链:一个类继承自另一个类,形成一个线性的链;
无重叠的多继承链:继承链无交叉,一个类同时继承自多个不同的类,无公共父类;
有重叠的多继承链:继承链有交叉,一个类同时继承自多个类,有公共父类

2.几种形态应该遵循的标准原则

Python3以上版本,三种继承链的访问顺序代码演示
# 单继承链
class C():
pass
class B(C):
pass
class A(B):
pass
#(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
import inspect
print(inspect.getmro(A))
# 无重叠的多继承链
class E(object):
pass
class D(object):
pass
class C(E):
pass
class B(D):
pass
class A(B,C):
pass
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>]
print(A.__mro__)
# 有重叠的多继承链
class D(object):
pass
class C(D):
pass
class B(D):
pass
class A(B,C):
pass
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
print(A.mro())
查看某一个类的资源查找顺序 的三种方式
# 方法1
import inspect
print(inspect.getmro(A))
# 方法2
print(A.__mro__)
# 方法3
print(A.mro())
3.针对于几种标准原则的方案演化
1.python不用版本方案演化



# python2.2中,检测不出的有问题的继承
# python3中,可检测出
# 多重继承中,确保每个基类只被继承一次,避免重复继承同一个基类
class D(object):
pass
class B(D):
pass
class C(B):
pass
class A(B,C):
pass
# TypeError: Cannot create a consistent method resolution
# order (MRO) for bases B, C
print(A.mro())

2.概念补充
MRO
深度优先
广度优先

C3算法


3.资源的覆盖
包括: 属性的覆盖,方法重写;
原理:
在MRO的资源检索链当中,
优先级比较高的类写了一个和优先级比较低的类一样的一个资源(属性或方法),
到时候,再去获取相关资源, 就会优先选择优先级比较高的资源;而摒弃优先级比较低的资源;造成”覆盖”的假象
# 资源的覆盖
class D(object):
pass
class C(D):
age='c'
def test(self):
print("test-c")
class B(D):
age = 'b'
def test(self):
print("test-b")
class A(B,C):
pass
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
print(A.mro())
print(A.age)#b
print(A().test())#test-b
注意事项:当调用优先级比较高的资源时,注意sel的变化。
class D(object):
pass
class C(D):
age='c'
def test(self):
print("test-c")
class B(D):
age = 'b'
def test(self):
print(self)
@classmethod
def test2(cls):
print(cls)
class A(B,C):
pass
a=A()
#谁调用这个方法,self,cls就是谁
a.test()#<__main__.A object at 0x0000025EF25E7430>
A.test2()#<class '__main__.A'>
4.资源的累加
概念:在一个类的基础之上,增加一些额外的资源;
class B:
a=1
def __init__(self):
self.b=2
def t1(self):
print('t1')
@classmethod
def t2(cls):
print("t2")
@staticmethod
def t3():
print("t3")
class A(B):
pass
# 1
# 2
# {'b': 2}
# t1
# t2
# t3
#调用了B中的__init__方法(相当于A继承了B的__init__方法),给a_obj实例增加了一个属性b=2
a_obj=A()
print(A.a)
print(a_obj.b)
print(a_obj.__dict__)
a_obj.t1()
a_obj.t2()
a_obj.t3()
子类相比于父类,多一些自己特有的资源;
class B:
a=1
def __init__(self):
self.b=2
def t1(self):
print('t1')
@classmethod
def t2(cls):
print("t2")
@staticmethod
def t3():
print("t3")
class A(B):
c=3
def __init__(self):
self.e=666
def tt1(self):
print('tt1')
@classmethod
def tt2(cls):
print("tt2")
@staticmethod
def tt3():
print("tt3")
pass
a_obj=A()
print(A.a)#1
# A中实现__init__方法后,这行代码报错,因为A创建实例(a_obj=A())时,就会自动调用自己的__init__,故不会给a_obj增加属性b
# print(a_obj.b)#AttributeError: 'A' object has no attribute 'b'
print(a_obj.__dict__)#{'e': 666}
a_obj.t1()
a_obj.t2()
a_obj.t3()
print(A.c)#3
a_obj.tt1()
a_obj.tt2()
a_obj.tt3()
a_obj.d='xxx'
print(a_obj.d)#xxx
print(a_obj.e)#666
在被覆盖的方法基础之上,新增内容
方案1(通过父类名调用)
class B:
a=1
def __init__(self):
self.b=2
self.xxx='555'
def t1(self):
print('t1')
@classmethod
def t2(cls):
print("t2")
@staticmethod
def t3():
print("t3")
class A(B):
c=3
def __init__(self):
#目的:给实例a新增属性
#self 就是a实例
#1.若使用实例调用(self.__init__),形成了死循环
# 2.若使用b实例调用,相当于给实例b增加属性(目的:给实例a新增属性)
# b=B()
# b.__init__()
#3.最终方案就是通过类名去调用
B.__init__(self)
self.e=666
def tt1(self):
print('tt1')
@classmethod
def tt2(cls):
print("tt2")
@staticmethod
def tt3():
print("tt3")
a=A()
print(a.__dict__)#{'b': 2, 'xxx': '555', 'e': 666}
弊端:
1.如果修改了父类名,那下面所有子类使用到父类名的地方都需要修改;
2.容易产生重复调用
#容易产生重复调用
class D(object):
def __init__(self):
print("d")
class C(D):
def __init__(self):
D.__init__(self)
print("c")
class B(D):
def __init__(self):
D.__init__(self)
print("b")
class A(B,C):
def __init__(self):
B.__init__(self)
C.__init__(self)
print("a")
# C()
# B()
#重复调用D.__init__
# d
# b
# d
# c
# a
A()
方案2(通过super调用)
在低优先级类的方法中,通过“super”调用高优先级类的方法。
1.概念:是一个类,只有在新式类中有效。
2.作用:
起着代理的作用,帮我们完成以下任务;
沿着MRO链条,找到下一级节点,去调用对应的方法
3.问题:
沿着谁的MRO链条?
找谁的下一节点?
如何应对类方法,静态方法以及实例方法的传参问题?
4.语法原理:
super(参数1[,参数2])
工作原理:
def super(cls,inst):
mro=inst.__class__.mro()
return mro[mro.index(cls)+1]
问题解决:
沿着谁的MRO链条?参数2
找谁的下一节点?参数1
如何应对类方法,静态方法以及实例方法的传参问题?使用参数2进行调用
5.常用具体语法形式
python2.2+
super(type,obj)->bound super object
super(type,type2)->bound super object
python3+
super()
class B:
a=1
def __init__(self):
self.b=2
self.xxx='555'
def t1(self):
print('t1')
@classmethod
def t2(cls):
print("t2")
@staticmethod
def t3():
print("t3")
class A(B):
c=3
def __init__(self):
#参数1:找A下一个节点
参数2:沿着A的mro链条找,因为调用的是__init__,所以使用self(填A或者A的子类都可以,都能找到A)
super(A,self).__init__()
self.e=666
def tt1(self):
print('tt1')
@classmethod
def tt2(cls):
print("tt2")
@staticmethod
def tt3():
print("tt3")
a=A()
print(a.__dict__)#{'b': 2, 'xxx': '555', 'e': 666}
class B:
a=1
def __init__(self):
self.b=2
self.xxx='555'
def t1(self):
print('t1')
@classmethod
def t2(cls):
print(cls)
print("t2")
@staticmethod
def t3():
print("t3")
class A(B):
c=3
def __init__(self):
# super(A,self).__init__()
super().__init__()
self.e=666
def tt1(self):
print('tt1')
@classmethod
def tt2(cls):
super(A,cls).t2()
print("tt2")
@staticmethod
def tt3():
print("tt3")
a=A()
# print(a.__dict__)#{'b': 2, 'xxx': '555', 'e': 666}
# <class '__main__.A'>
# t2
# tt2
a.tt2()
#菱形继承
# super解决重复调用问题
class D(object):
def __init__(self):
print("d")
class C(D):
def __init__(self):
super().__init__()
print("c")
class B(D):
def __init__(self):
super().__init__()
print("b")
class A(B,C):
def __init__(self):
super().__init__()
print("a")
# d
# c
# b
# a
A()
6.注意
super().__init__(),super的第一个参数不要使用self.__class__,容易产生死循环;
super().__init__()和父类名.__init__(self) 不要共用,会产生重复调用。
3.多态
多态:
一个类,所延伸的多种形态;
调用时的多种形态:在继承的前提下,使用不同的子类,调用父类的同一个方法,产生不同的功能。
多态在Python中的体现:
鸭子类型:
动态类型的一种风格;
只要一个对象,会走会游泳,会叫,那它就可以当做一个鸭子进行处理;
关注点在于对象的“行为和属性”,而非对象的“类型”;
所以,在Python当中,没有真正意义上的多态,也不需要多态。
class Animal(object):
def jiao(self):
pass
class Dog(Animal):
def jiao(self):
print("汪汪汪")
class Cat(Animal):
def jiao(self):
print("喵喵喵")
def test(obj):
obj.jiao()
d=Dog()
test(d)#汪汪汪
c=Cat()
test(c)#喵喵喵
4.补充:抽象类,抽象方法
抽象类
一个抽象出来的类,并不是某一个具化的类;
不能直接创建实例的类,创建会报错
抽象方法
抽象出来的一个方法;
不具备具体实现,不能直接调用,子类不实现会报错
Python中的实现
无法直接支持,需要借助一个模块 import abc
设置类的元类为 abc.ABCMeta
使用装饰器修饰抽象方法 @abcabstractmethod
#抽象类,抽象方法
import abc
class Animal(object,metaclass=abc.ABCMeta):
@abc.abstractmethod
def jiao(self):
pass
@abc.abstractclassmethod
def run(cls):
pass
@abc.abstractstaticmethod
def eat():
pass
class Dog(Animal):
def jiao(self):
print("汪汪汪")
@classmethod
def run(cls):
print("dog跑")
@staticmethod
def eat():
print("dog吃")
class Cat(Animal):
def jiao(self):
print("喵喵喵")
def test(obj):
obj.jiao()
#TypeError: Can't instantiate abstract class Animal with abstract methods eat, jiao, run
# a=Animal()
# a.jiao()
# 汪汪汪
# dog跑
# dog吃
d=Dog()
d.jiao()
d.run()
d.eat()





![[C++探索之旅] 第一部分第十一课:小练习,猜单词 - 鹿快](https://img.lukuai.com/blogimg/20251015/da217e2245754101b3d2ef80869e9de2.jpg)










暂无评论内容