python类和对象-面向对象三大特性(封装,继承,多态)超详细

目录

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是根:所有类都继承自
object
type是创建者:所有类都是
type
的实例循环关系
type
继承自
object
,而
object
又是
type
的实例统一模型:这种设计使得Python中的所有东西都是对象,包括类本身



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()

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
poP丶xX的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容