2021小白Python学习记录Day8 面向对象基础(中) (析构方法 单继承 多继承 继承的传递 重写父类方法 调用父类方法 类属性的实例属性 类方法和静态方法 多态 )

'''

在python中展现面向对象的三大特征:封装、继承、多态。

前面我们讲了封装,下面我们来学习继承和多态。

'''

目录

一 、析构方法

二、继承

1.单继承

2.多继承

多继承案例

多继承同名方法继承顺序 间接继承

3.重写和调用父类方法

三.属性和方法

1.类属性

2.类方法和静态方法

四、多态

多态概念

多态的利用:“鸭子类型”


一 、析构方法

        当一个对象被删除或者被销毁时,python解释器也会默认调用一个方法,这个方法为__del__()方法,也称为析构方法

# # __del__()
class Animal:
    def __init__(self,name):
        self.name=name
        print('这是__init__构造初始化方法,构造%s 对象'%(self.name))
        pass
    def __del__(self):     #(定义类时可以不用写)
        #主要的应用就是用来操作 对象的释放 一旦释放完毕 对象便不能再使用  (定义类时可以不用写)
        print('这是__del__析构方法')
        print('当某个作用域下面,没有被使用【引用】的情况下 解释器会自动调用此函数 来释放内存空间')
        print('%s 对象被彻底清理了 内存开销也释放了'%(self.name))
    pass
cat=Animal('小花猫')

print('----------------')

dog=Animal('拉布拉多')
del dog            #可以用del手动删除对象
input('程序等待中...')    #制造一个暂停 按下回车继续
print('--------------------')

运行结果:

 可以看到我们使用 del dog 时 dog 对象被__del__方法析构了

按下回车:

 小花猫对象在程序运行结束时自动调用了__del__方法

析构方法总结

1、当整个程序脚本执行完毕后会自动调用__del__方法

2、当对像被手动销毁时也会自动调用 __del__ 方法

3、析构函数一般用于资源回收,利用__del__方法销毁对象回收内存等资源

二、继承

# python3 类默认继承object

继承:和现实生活当中的继承是一样的:也就是 子可以继承父的内容【属性和行为】
(爸爸有的儿子都有,儿子有的爸爸不一样有)父类:基类   子类:派生类
代码中其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必 重新编写共有方法
提高效率 减少代码的重复编写 精简代码的层级结构  便于拓展

1.单继承

单继承
class 类名(父类):
    pass

先写一个父类:

# 单继承
class Animal:
    def eat(self):
        '''
        吃
        :return:
        '''
        print('吃')
        pass
    def drink(self):
        '''
        喝
        :return:
        '''
        print('喝')
        pass
    pass

再让子类去继承这个父类:

class Dog(Animal):       # 继承Animal 父类 此时Dog就是子类
    def wwj(self):
        '''
        子类独有的实现
        :return:
        '''
        print('汪汪叫')
        pass
class Cat(Animal):
    def mmj(self):
        print('喵喵叫')
        pass
d1=Dog()
d1.eat()          # 具有了吃的行为即继承了父类Animal的行为
d1.wwj()

运行结果:

Dog子类也拥有了Animal父类的行为。

2.多继承

子类可以继承一个父类,那是否可以继承两个父类或多个呢?

答案是肯定的,这就是python的多继承

多继承
class 类名(父类1,父类2):
    pass

多继承案例

class Shenxian:
    def fly(self):
        print('会飞')
    pass
class Monkey:
    def fly(self):
        print('猴子想飞')
    def chitao(self):
        print('猴子喜欢吃桃')
    pass
class Sunwukong(Shenxian,Monkey):
    pass
swk=Sunwukong()
swk.fly()      # 输出 会飞  而不是 '猴子想飞' 继承顺序 先左右 后辈分(广度优先)
swk.chitao()

运行结果:

Sunwukong这个子类继承了Shenxian,Monkey两个父类

swk.fly()  Shenxian,Monkey两个父类都有fly方法  输出的是会飞 而不是 '猴子想飞' 

这里涉及到类继承顺序的问题  【先左右 后辈分(广度优先)】

多继承同名方法继承顺序 间接继承

# 多继承同名方法继承顺序间接继承
class D():
    def eat(self):
        print('D.eat')
    pass
class C(D):
    def eat(self):           #重写父类方法  [子类方法(再子类中)覆盖了父类同名方法]
        print('C.eat')
    pass
class B(D):
    pass
class A(B,C):   # 找B没有 就找C 而不是向上找D
    pass
a=A()
a.eat()       # C.eat          继承顺序 先左右 后辈分 (广度优先) 一辈遍历完了 进入上一辈
print(A.__mro__) #(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)

运行结果:

__mro__ 方法解析顺序:

在前面的代码中,我们使用了 __mro__ 方法

功能:查询执行顺序。

在执行eat 的方法时 查找方法的顺序是
首先到A-A中没有-去B-B没有-去C(广度优先)找到  如果没找到再去D然后到object 再没找到就报错

3.重写和调用父类方法

#  子类中,有一个和父类相同的名字的方法,在子类中的方法会覆盖吊父类中的同名方法
#  为什么要重写:父类的方法已经不满足子类的需求,那么子类就可以重写父类或者 完善父类方法
class Dog:
    def bark(self):
        print('汪汪叫...')
        pass
    pass

class AnimAl:
    def __init__(self,name,color,ctm):
        self.name=name
        self.color=color
        self.ctm=ctm

class Kejiquan(Dog,AnimAl):
    def __init__(self,name1,color1,ctm1):        #属于重写父类方法
        # 针对这种诉求 我们就需要去调用父类方法
        #Dog.__init__(self,name,color)  #手动调用父类方法 就可以具备name 和color这个两个实例属性了
        super(Kejiquan, self).__init__(name1,color1,ctm1)
        #super 是自动找到父类 进而调用方法 多继承时 会按照顺序逐个去找 再调用
        # 拓展其他的属性
        self.height=90
        self.weight=30
        pass
    def __str__(self):   # 输出对象时按照这个方法打印 没有这个方法不能直接输出
        return '{}的颜色会{} 它的身高{}cm 体重是{}kg  {}'.format(self.name,self.color,self.height,self.weight,self.ctm)
    def bark(self):
        super(Kejiquan, self).bark()       #调用父类方法
        print('叫得很大声...')     #属于重写父类方法
    pass
kj=Kejiquan('柯基','红色','100')            #实例化默认调用父类__init__
kj.bark()
print(kj)      # 柯基的颜色会红色 它的身高90cm 体重是90

 运行结果:

 可以看到这里是调用子类的bark方法

三.属性和方法

1.类属性

类属性  就是类对象所拥有的属性
class Student:
    pro='上学'  #属于类属性  Student类对象所拥有
    def __init__(self,age):
        self.age=age    #实例属性
        pass
    pass
lm=Student(18)
print(lm.age,lm.pro)   # 18 上学   pro 先找自己的实例属性 再找类属性
lm.pro='上班'    # lm变(成了实例属性了) xh不变
print(lm.age,lm.pro)   # 18 上学   pro 先找自己的实例属性 再找类属性

xh=Student(21)
print(xh.pro)    #上学
print('------------通过类对象Student访问类对象-------------')
print(Student.pro)          #   类名.类属性    上学
Student.pro='业务'       #更改类属性
print(xh.pro,lm.pro)       #  业务 上班    xh变了  lm维持上次变化

运行结果:

类属性是可以被类对象和实例对象共同访问使用。实例属性只能被实例对象访问使用。

但是当实例对象的实例属性与类属性同名时,实例属性优先。

2.类方法和静态方法

# 类方法  # 静态方法
class People:
    country='China'
    # 类方法用 @classmethod 来进行修饰
    @classmethod
    def get_country(cls):
        return cls.country    #访问类属性
    @classmethod
    def change_country(cls,data):
        cls.country=data    #修改类属性的值  在类方法中
    # 静态方法用 @staticmethod  来进行修饰
    @staticmethod
    def getData():   #静态方法
        return People.country
    pass
print(People.get_country())        # China   通过类对象去引用
P=People()
print('实例对象访问类方法%s'%P.get_country())    # 实例对象访问类方法China
People.change_country('英国')
print('----------修改后-----------')
print(People.get_country())  #  英国
print(P.get_country())    #  英国

print(People.getData())         #英国  调用静态方法
print(P.getData())      # 注意一般情况下 不用实例对象去访问静态方法

运行结果:

类方法可以被类对象和实例对象使用。实例方法只能被实例对象使用。

为什么要使用静态方法呢:

由于静态方法主要来存放逻辑性的代码,本身和类以及实例对象没有交互

也就是说,在静态方法中,不会设计到类中方法和属性的操作

数据资源能够得到有效的充分利用

四、多态

多态概念

所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态。

Pyhon不支持Java和C#这一类语言中多态的写法,但是原生多态,Python崇尚“鸭子类型”,利用python伪代码实现Java和C#的多态

# 多态
class Animal:
    '''
    父类【基类】
    '''
    def sayWho(self):
        print('我是一个动物...')
        pass
    pass
class Duck(Animal):
    '''
     鸭子类  子类【派生类】
    '''
    def sayWho(self):
        print('我是一只鸭子')
    pass
class Dog(Animal):
    '''
     小狗类  子类【派生类】
    '''
    def sayWho(self):
        print('我是一只小狗')
    pass
class Cat(Animal):
    '''
     小猫类  子类【派生类】
    '''
    def sayWho(self):
        print('我是一只小猫,喵喵喵')
    pass

duck1=Duck()
duck1.sayWho()   #我是一只鸭子
dog1=Dog()
dog1.sayWho()    #我是一只小狗       多态

多态的利用:“鸭子类型”

紧接上面的代码:

class People:        #未继承Animal
    def sayWho(self):
        print('我是一个人')
    pass

def commonInvoke(obj):
    '''
    统一调用的方法
    :param obj: 对象的实例
    :return:
    '''
    obj.sayWho()

listObj=[Duck(),Dog(),Cat(),People()]       # 多态利用 优势
for item in listObj:
    '''
    循环去调用函数
    '''
    commonInvoke(item)     #'python鸭子类型'(duck typing) 鸭子类型中不关注对象本身,只关注它如何的使用 在其他语言不成立
    pass

运行结果:

在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。 “鸭子测试”可以这样表述: “当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。” 在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿左.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值