Python面向对象基础(中)—Python Day8

重点:类的继承、父类的调用 、静态方法
难点:继承与重写、静态方法

析构方法

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

class Animal():
    def __init__(self,name):
        self.name=name
        print('__init__方法被调用')
        #析构方法,当对象被销毁时,python解析器会自动调用
    def __del__(self):
        print('__del__方法被调用')
        print('%s 对象被销毁'%self.name)

dog=Animal("旺财")
input('程序等待中.....')

程序执行结束自动调用__del__方法

--------------输出结果---------------
__init__方法被调用
程序等待中.....111
__del__方法被调用
旺财 对象被销毁

对象被删除时也会自动调用__del__方法,如下代码中我们利用del手动删除dog对象

class Animal():
    def __init__(self,name):
        self.name=name
        print('__init__方法被调用')
        #析构方法,当对象被销毁时,python解析器会自动调用
    def __del__(self):
    	#主要用于对象的释放,一旦释放,对象不再使用
        print('__del__方法被调用')
        print('%s 对象被销毁'%self.name)

dog=Animal("旺财")
del dog  #删除对象..........
input('程序等待中.....')
--------------输出结果---------------
__init__方法被调用
__del__方法被调用
旺财 对象被销毁
程序等待中.....111

析构方法总结
1、当整个程序脚本执行完毕后会自动调用__del__方法
2、当对像被手动销毁时也会自动调用 del 方法
3、析构函数一般用于资源回收,利用__del__方法销毁对象回收内存等资源

单继承

继承的概念
在现实生活中,继承一般指的是子女继承父辈的财产。在面向对象中同样有继承,例如:
猫的方法:喵喵叫、吃、喝
狗的方法:汪汪叫、吃、喝
如果给猫和狗都创建一个类,那么猫和狗的所有方法都要写,如:

class cat:
    def call_Mao(self):
        print('喵喵喵')
    def eat(self):
        print('鱼')
    def drink(self):
        print('water')
class dog:
    def call_Wang(self):
        print('汪汪汪')
    def eat(self):
        print('骨头')
    def drink(self):
        print('water')

上面的代码中我们可以发现,吃,喝方法时一样的,但是写了两遍。
如果用继承的思想,我们可以这样:猫和狗都是动物(动物有吃,喝的方法)
继承方法

print('-------------继承写法------------')
class Animal():
    # 父类的实现
    def eat(self):
        print('爱吃东西')
        pass
    def drink(self):
        print('爱喝水')
        pass
class cat(Animal): #继承了Animal的方法
    #子类的独有实现
    def mmj(self):
        print('喵喵喵')
class dog(Animal):  #继承了Animal的方法
    # 子类的独有实现
    def wwj(self):
        print('汪汪汪')
dog1=dog()
dog1.eat()
dog1.drink()

cat1=cat()
cat1.eat()
cat1.drink()
-------------输出结果------------
爱吃东西
爱喝水
爱吃东西
爱喝水

所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法

class 类名(父类):
	#子类就可以继承父类中公共的属性和方法
	pass

总结:在定义子类时要继承父类,只需要类名后面的小括号()中写上父类的名字,那么父类的属性、方法,会被继承给子类。

多继承

多继承概念
子类可以继承一个父类,那是否可以继承两个父类或多个呢?答案是肯定的,这就是python的多继承
在这里插入图片描述

C类可以继承A、B两个类, 可以将A,B中的方法继承过来,C拥有A,B的方法和属性

class A():
    def a(self):
        print('A类的方法输出')
class B():
    def b(self):
        print('B类的方法输出')
#C继承AB
class C(A,B):
    pass
c=C()
c.a()
c.b()
-------------输出结果------------
A类的方法输出
B类的方法输出

同名方法
如果在上面的多继承例子中,如果父类A和父类B中,有一个同名的方法,那么通过子类去调用的时候,调用哪个?

class Base():
    def test(self):
        print('------Base test------')
class Base1():
    def test(self):
        print('------Base1 test------')
class A(Base):
    def test(self):
        print('--------A test--------')
class B(Base1):
    def test(self):
        print('--------B test--------')
class C(A,B):
    pass
c=C()
c.test()
print(C.__mro__) # 可以查看C类的对象搜索方法是的先后顺序,也就是继承的顺序
-------------输出结果------------
--------A test--------
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.Base'>, <class '__main__.B'>, <class '__main__.Base1'>, <class 'object'>)

同名方法:按先后顺序继承
mro 方法解析顺序
在前面的代码中,我们使用了 mro 方法
功能:查询执行顺序
描述:方法的执行顺序可以用mro查看。前面代码查找顺序为 C->A->Base->B>Base1, 一旦找到,则寻找过程立即中断,便不会再继续找了

继承的传递

在现实中遗产继承,爷爷的遗产可以被父亲继承,儿子可以继承父亲的。这样看来是不是儿子也是有继承到爷爷的遗产。在面向对象中的继承呢?子类是否能继承父类的父类的方法?

看看下面的继承关系,Son类继承Father类,Father类并没有提供eat方法,但是父类又继承了Grandfather类。Son的对象调用eat方法可以正常执行,运行结果得出,Son类也继承了Granderfather类的方法。这就是继承的传递性

class GrandFather():
    def eat(self):
        print('吃饭')
class Father(GrandFather):
    def drink(self):
        print('喝水')
class Son(Father):
    pass
Lg=Son()
Lg.eat()
Lg.drink()
-------------输出结果------------
吃饭
喝水

父辈继承了爷爷辈,儿子继承了父辈,所以儿子可以调用爷爷辈的方法
总结:类的传递过程中,我们把父类又称为基类,子类又称为派生类,父类的属性和方法可以一级一级的传递到子类

重写父类方法

所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法 伪代码示例:

class GrandFather():
    def eat(self):
        print('吃饭')
class Father(GrandFather):
    def eat(self):
        print('经常吃烧烤')  #在父类覆盖方法
    def drink(self):
        print('喝水')
class Son(Father):
    pass
Lg=Son()
Lg.eat()   #是从GrandFather继承过来的  只是在Father中北覆盖了
Lg.drink()
-------------输出结果------------
经常吃烧烤
喝水

调用父类方法

class Dog():
    def __init__(self,name,colour):
        self.name=name
        self.colour=colour
    def bark(self):
        print('汪汪叫')
class KeJiDog(Dog):
    def __init__(self,name,colour): #属于重写init方法
        #Dog.__init__(self,name,colour) # 手动调用
        #调用父类的方法,执行完毕就可以具备name,colour这两个实例属性了
        #扩展其他属性
        super().__init__(name,colour)  #super是自动找父类,进而调用方法
        self.height=90
        self.weight=20
        pass
    def __str__(self):
        return '{}的颜色是,他的身高是{},体重是{}'.format(self.name,self.height,self.weight)
    def bark(self):   #属于重写bark方法
        super().bark()  #调用父类方法
        print('叫的跟神一样')
        pass
kj=KeJiDog('科技犬','红色')
kj.bark()
print(kj)
-------------输出结果------------
汪汪叫
叫的跟神一样
科技犬的颜色是,他的身高是90,体重是20

多态

多态概念
所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态。
Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,Python崇尚“鸭子类型”,利用python伪代码实现Java和C#的多态

要想实现多态,必须要有2个前提要遵守:
1.继承关系,多态必须发生在父类和子类之间
1.重写 子类要重写父类的方法

class Animal:
    '''
    父类【基类】
    '''
    def Say(self):
        print('我是一个动物.....')
        pass
class Duck(Animal):
    '''
    鸭子类 【子类】 派生类
    '''
    def Say(self):
        '''
        在这里重写父类的方法
        :return:
        '''
        print('我是一只漂亮的鸭子')
        pass
class Dog(Animal):
    '''
    小狗类 【子类】 派生类
    '''
    def Say(self):
        '''
        在这里重写父类的方法
        :return:
        '''
        print('我是一只可爱的小狗')
        pass
class Cat(Animal):
    '''
    小狗类 【子类】 派生类
    '''
    def Say(self):
        '''
        在这里重写父类的方法
        :return:
        '''
        print('我是一只可爱的猫咪')
        pass
duck=Duck()
duck.Say()
dog=Dog()
dog.Say()
cat=Cat()
cat.Say()

多态案例
Python 天生就是支持多态,因为他是弱类型语言,不需要指定类型。 Python“鸭子类型”。

class Animal:
    '''
    父类【基类】
    '''
    def Say(self):
        print('我是一个动物.....')
        pass
class Duck(Animal):
    '''
    鸭子类 【子类】 派生类
    '''
    def Say(self):
        '''
        在这里重写父类的方法
        :return:
        '''
        print('我是一只漂亮的鸭子')
        pass
class Dog(Animal):
    '''
    小狗类 【子类】 派生类
    '''
    def Say(self):
        '''
        在这里重写父类的方法
        :return:
        '''
        print('我是一只可爱的小狗')
        pass
class Cat(Animal):
    '''
    小狗类 【子类】 派生类
    '''
    def Say(self):
        '''
        在这里重写父类的方法
        :return:
        '''
        print('我是一只可爱的猫咪')
        pass
class People():  #虽然不同类  但同样有Say方法  就能被统一调用
    def Say(self):
        print('我是人类')
        pass
class Student(People):  #虽然不同类  但同样有Say方法  就能被统一调用
    def Say(self):
        print('我是学生小明')
        pass
#  多态的只需增加以下代码 就可以执行
def CI(obj):
    obj.Say()  #都具备Say的方法 就可以统一调用
ListObj=[Duck(),Dog(),Cat(),People(),Student()]
for item in ListObj:
     CI(item)
-------------输出结果------------
我是一只漂亮的鸭子
我是一只可爱的小狗
我是一只可爱的猫咪
我是人类
我是学生小明

多态的作用 只要具备这个方法 不管类型都能调用,能简化代码

类属性和实例属性

类属性的概念
类属性:就是类对象所拥有的属性,它被所有类对象的实例对象所共有,类对象和实例对象可以访问
实例属性的概念
实例属性:实例对象所拥有的属性,只能通过实例对象访问

print('------通过实例对象去访问类属性-------')
class Student:
    name='李明辉' #属于类属性  就是student类对象所拥有的
    def __init__(self,age):
        self.age=age
        pass
    pass
lm=Student(18)
print(lm.name)  #通过实例对象去访问类属性
lm.name='刘德华'  #通过实例对象,对类属性进行修改,可以吗?不可以
print(lm.age)
print(lm.name)  #输出‘刘德华’只是临时的修改实例属性,不会修改类的
xh=Student(18)
print(xh.age)
print(xh.name)   #输出‘李明辉’类属性没有被改变
print('------通过类对象student去访问name-------')
print(Student.name)  #本身name就是类属性所有
#print(Student.age)  #会报错,实例属性age不能被类属性访问

Student.name='李易峰'  #通过类对象才能去修改
xh=Student(18)
print(xh.age)
print(xh.name)   #输出‘李易峰’类属性改变啦
-------------输出结果------------
------通过实例对象去访问类属性-------
李明辉
18
刘德华
18
李明辉
------通过类对象student去访问name-------
李明辉
18
李易峰

从上面的的案例可以得出:

如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性

类方法和静态方法

类方法
类对象所拥有的方法,需要用装饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数,类方法可以通过类对象,实例对象调用

class People:
    country='china'
    #类方法 需要用classmethod 来进行修饰
    @classmethod
    def get_country(cls):
        return cls.country  #访问类属性
    pass
    @classmethod
    def change_country(cls,data):
        cls.country=data  #修改类属性的值  在类方法中
    pass
print(People.get_country())
p=People()
print('实例对象访问%s'%p.get_country())

People.change_country('英国')
print(People.get_country())
-------------输出结果------------
china
实例对象访问china
英国

类方法主要可以对类属性进行访问、修改
静态方法
类对象所拥有的方法,需要用@staticmethod来表示静态方法,静态方法不需要任何参数,如:
为什么要使用静态方法?
由于静态方法主要来存放逻辑性的代码,本身和类以及实例对象没有交互,也就是说,在静态方法中,不会涉及到类中方法和属性的操作
数据资源能够得到有效的利用

class People:
    country='china'
    #类方法 需要用classmethod 来进行修饰
    @classmethod
    def get_country(cls):
        return cls.country  #访问类属性
    pass
    @classmethod
    def change_country(cls,data):
        cls.country=data  #修改类属性的值  在类方法中
    pass
    @staticmethod
    def getData(): 
        return People.country   #通过类对象去引用
print(People.getData())
p=People()
print(p.getData())


import time
class TimeTest:
    def __init__(self,hour,min,second):
        self.hour=hour
        self.min = min
        self.second = second

    @staticmethod
    def showTime():
         return time.strftime('%H:%M:%S',time.localtime())

print(TimeTest.showTime())
t=TimeTest(2,10,15)
print(t)
-------------输出结果------------
china
china
20:20:30
<__main__.TimeTest object at 0x0000023C42C6DCD0>

类方法、实例方法、静态方法对比
1.类方法的第一个参数是类对象cls,通过cls引用的类对象的属性和方法
2.实例方法的第一个参数是实例对象self,通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。
3.静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值