Day-8-面向对象基础(中)

Day-8-面向对象基础(中)_第1张图片

一、析构方法

1、析构方法的概述

Day-8-面向对象基础(中)_第2张图片

其实析构方法就是对象删除销毁时,项目需要进行对应的提示和操作

2.定义

Day-8-面向对象基础(中)_第3张图片

3.实例

class Animal:
    def __init__(self,name):
        self.name=name
        print("这是构造初始化方法")
        pass
    def __del__(self):
        print('当在某个作用域下面,没有被使用【引用】的情况下,解释器会自动的调用此函数,来释放内存空间')
        print("这是析构方法")
    pass
cat=Animal('小花猫')

Day-8-面向对象基础(中)_第4张图片

我们可以看到,是先构造后析构,然后对象被清理后会自动执行析构函数

4.手动删除

Day-8-面向对象基础(中)_第5张图片

5.总结

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

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

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

二、单继承

1、简述

在python中展现面向对象的三大特征:

封装、继承、多态

  • 封装;指的是把内容封装到某个地方,便于后面的使用

他需要:把内容封装到某个地方,从另外一个地方去调用被封装的内容,对于封装来说,其实就是使用初始化构造方法将内容封装到对象中,然后通过对象直接或者self来获取封装的内容

  • 继承:和现实生活当中的继承是一样的:也就是子可以继承父的内容【属性和行为】(爸爸有的,儿子都有,相反,儿子有的,爸爸不一定有)

2.继承的概念

在现实生活中,继承一般指的是子女继承父辈的财产。在面向对象中同样有继承,例如:

猫的方法:喵喵叫、吃、喝

狗的方法:汪汪叫、吃、喝

如果给猫和狗都创建一个类,那么猫和狗的所有方法都要写,如:

Day-8-面向对象基础(中)_第6张图片

3.继承的写法

上面的代码中我们可以发现,吃,喝方法时一样的,但是写了两遍。

如果用继承的思想,我们可以这样:猫和狗都是动物(动物有吃,喝的方法)

Day-8-面向对象基础(中)_第7张图片

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

4.案例

案例中子类没有写任何方法,但是直接调用eat方法没有报错,这说明子类继承了父类的方法。

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

class Animal:
    def eat(self):
        '''
        子类共同的行为
        吃
        :return:
        '''
        print('吃饭了')
    def drink(self):
        '''
        喝
        :return:
        '''
        print('喝水了')
class Dog(Animal):#继承了Animal 父类,此时Dog就是子类
    def wwj(self):
        '''
        子类独有的行为
        :return:
        '''
        print('小狗汪汪叫')
    pass
class Cat(Animal):#继承了Animal 父类,此时Cat就是子类
    def mmj(self):
        print('小猫喵喵叫')
d1=Dog()
d1.eat()#继承了父类的行为
print('*'*30)
c1=Cat()
c1.drink()
Day-8-面向对象基础(中)_第8张图片

所以对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需要继承父类,而不必去一一实现,这样就可以极大的提高效率,减少代码的重复编写,精简代码的层级结构,便于拓展

class 类名(父类)

三、多继承

1.概念

子类可以继承一个父类,那是否可以继承两个父类或多个呢?答案是肯定的,这就是python的多继承

Day-8-面向对象基础(中)_第9张图片

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

2.案例

Day-8-面向对象基础(中)_第10张图片

在C类中并没有写方法,只继承了A,B两个父类。C可以调用两个父类的方法

class shenxian:
    def fly(self):
        print('神仙会飞')
        pass
class monkey:
    def chitao(self):
        print('猴子喜欢吃桃')
class sunwukong(shenxian,monkey):
    pass
swk=sunwukong()
swk.fly()
swk.chitao()

输出结果:

Day-8-面向对象基础(中)_第11张图片

3.多个父类中的同名方法

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

Day-8-面向对象基础(中)_第12张图片

4.同名方法实操

class D(object):
    def eat(self):
        print('D.eat')
        pass
    pass
class C(D):
    def eat(self):
        print('C.eat')
        pass
    pass
class B(D):
    pass
class A(B,C):
    pass
a=A()
#在执行eat()方法的查找顺序
#首先到A里面去查找,如果A中没有,则继续到B中查找,如果B中查找没有,到C中进行查找,
#如果C没有,就到D中查找,如果还是没有找到就报错
#采取的是广度优先查找
a.eat()
print(A.__mro__)#可以显示类的继承关系

5.__mro__ 方法解析顺序

Day-8-面向对象基础(中)_第13张图片

四、继承的传递

1.概念

Day-8-面向对象基础(中)_第14张图片

2.案例

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

class GrandFather:
    def eat(self):
        print('吃的方法')
        pass
    pass
class Father(GrandFather):
    pass
class Son(Father):
    pass
son=Son()
son.eat()#此方法是从GrandFather基础过来的
print(Son.__mro__)

输出结果:

总结:类的传递过程中,我们把父类又称为基类,子类又称为派生类,父类的属性和方法可以一级一级的传递到子类

五、重写父类方法

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

Day-8-面向对象基础(中)_第15张图片

为什么要重写:父类的方法已经不能满足子类的需要,子类就可以重写父类的方法

class Dog:
    def bark(self):
        print('汪汪叫.....')
class keji(Dog):
    def bark(self):
        print('柯基叫')
kj=keji()
kj.bark()

六、调用父类方法

如果在子类中有一个方法需要父类的功能,并且又要添加新的功能。如果直接重写父类方法,那么就要重复写很多代码。那么这就要调用父类方法

Day-8-面向对象基础(中)_第16张图片
class Dog:
    def __init__(self,name,color):
        self.name=name
        self.color=color
    def bark(self):
        print('汪汪叫.....')
class keji(Dog):
    def __init__(self,name,color):#属于重写父类的方法
        #我们需要去调用父类的构造函数
        Dog.__init__(self,name,color)#显示调用父类的构造函数,就可以子类具备父类的实例属性
        #扩展其他的属性
        super(keji, self).__init__(name,color)#super是自动找到父类的调用方法
        #假设有多个父类,会按照广度优先查找,找到了就调用
        self.height=90
        self.weight=20
        pass
    def __str__(self):
        return '{}的颜色是{},身高是{}cm,体重是{}kg'.format(self.name,self.color,self.height,self.weight)
    def bark(self):#属于重写父类的方法
        super(keji, self).bark()#调用父类方法
        # 假设有多个父类,会按照广度优先查找,找到了就调用
        print('柯基叫')

kj=keji('柯基','黄色')
kj.bark()
print(kj)

结果:

Day-8-面向对象基础(中)_第17张图片

七、类属性和实例属性

1.类属性

类属性:就是类对象所拥有的属性,它被所有类对象的实例对象所共有,类对象和实例对象可以访问

2.实例属性的概念

实例属性:实例对象所拥有的属性,只能通过实例对象访问

#属性和实例属性
#类属性 就是类对象所拥有的属性
class Student:
    name="李明"#属于类属性,就是student类对象所拥有的
    def __init__(self,age):
        self.age=age
        pass
    pass
lm=Student(18)
print(lm.name)#通过实例对象去访问类属性
print(lm.age)
#类属性是可以被类对象和实例对象共同访问使用
#实例属性只能由实例对象来访问
#顺序:先查找实例属性中查找->类属性查找
Day-8-面向对象基础(中)_第18张图片

3.访问原理

类属性类对象可以访问,实例对象也可以访问,这与内存中保存的方式有关

Day-8-面向对象基础(中)_第19张图片

上图中可以看出,所有实例对象的类对象指针指向同一类对象。实例属性在每个实例中独有一份,而类属性是所有实例对象共有一份

4.类属性修改与访问

Day-8-面向对象基础(中)_第20张图片

要想修改类属性,采用类名.类属性进行修改

八、类方法和静态方法

1.类方法的概念

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

2.类方法案例

Day-8-面向对象基础(中)_第21张图片

类方法主要可以对类属性进行访问、修改

class People:
    country='China'
    @classmethod #加上修饰后,下面的这个方法就成为了类方法
    def get_country(cls):
        return cls.country #访问类属性
        pass
    @classmethod
    def change_country(cls,data):
        cls.country=data #在类方法中修改类属性的值
    pass
print(People.get_country())#通过类对象直接引用
p1=People()
print('实例对象访问%s'%p1.get_country())
print('***'*10)
People.change_country('英国')
print(People.get_country())#通过类对象直接引用
Day-8-面向对象基础(中)_第22张图片

3.静态方法概念

类对象所拥有的方法,需要用@staticmethod来表示静态方法,静态方法不需要任何参数,如:

Day-8-面向对象基础(中)_第23张图片

4.静态方法案例

#为什么要使用静态方法?

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

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

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

class People:
    country='China'
    @staticmethod
    def getData():
        return People.country
print(People.getData())
p=People()
print(p.getData())
#注意,一般情况下,我们不会通过实例对象去访问静态方法

#demo 返回当前的系统时间
import time #引入时间模块
class TimeTest:
    def __init__(self,hour,min,second):
        self.hour=hour
        self.min=min
        self.second=second
    @staticmethod
    def shoeTime():
        return time.strftime("%H:%M:%S",time.localtime())
print(TimeTest.shoeTime())
Day-8-面向对象基础(中)_第24张图片

5.类方法、实例方法、静态方法对比

类方法的第一个参数是类对象cls,通过cls引用的类对象的属性和方法,必须用装饰器【@classmethod】

实例方法的第一个参数是实例对象self,通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。

静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象【或者实例对象】来引用。必须用装饰器【@staticmethod】

九、多态

1.概念

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

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

【就是多种状态,多种形态,就是同一种行为对于不同的子类【对象】有不同的行为表现】

实现多态的前提:

  1. 必须存在继承关系:多态必须发送在父类和子类之间

  1. 重写:子类重写父类方法

2.鸭子类型

在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。 “鸭子测试”可以这样表述:

“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”

在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的

3.案例

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

Day-8-面向对象基础(中)_第25张图片

class Animal:
    '''
    父类【基类】
    '''
    def say_who(self):
        print('我是一个动物...')
        pass
    pass
class Duck(Animal):
    '''
    鸭子类【子类】【派生类】
    '''
    def say_who(self):
        '''
        在这里重写父类的方法
        :return:
        '''
        print('我是一只漂亮的鸭子')
        pass
    pass
class Dog(Animal):
    '''
    小狗类【子类】【派生类】
    '''
    def say_who(self):
        '''
        在这里重写父类的方法
        :return:
        '''
        print('我是一只哈巴狗')
        pass
    pass
class Cat(Animal):
    '''
    小猫类【子类】【派生类】
    '''
    def say_who(self):
        '''
        在这里重写父类的方法
        :return:
        '''
        print('我是一只小猫')
        pass
    pass
def commonInvoke(obj):
    '''
    统一调用方法
    :param obj: 对象的实例
    :return:
    '''
    obj.say_who()
listobj=[Duck(),Dog(),Cat()]
for item in listobj:
    commonInvoke(item)
'''
duck1=Duck()
duck1.say_who()
dog1=Dog()
dog1.say_who()
cat1=Cat()
cat1.say_who()
'''

4.总结

多态:

  • 可以增加程序的灵活性

  • 增加程序的扩展性

你可能感兴趣的:(个人python学习笔记,开发语言,python)