• python学习笔记-09


    面向对象编程-中

    面向对象三大特征:封装、继承、多态。

    封装:把内容封装起来便于后面的使用。对于封装来讲,就是使用__init__方法将内容封装道对象中,然后通过对象直接或者self获取被封装的内容。

    继承:子继承父的属性和方法。

    多态:所谓多态就是定义时的类型和运行时的类型不一样,同一种行为对于不同的子类对象有不同的行为表现。python不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,“鸭子类型”。

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

    1.析构函数

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

    一般来讲程序执行结束自动调用此方法。

    #析构方法
    class Animal:
        def __init__(self,name):
            self.name=name
            print('init方法调用,初始化%s对象'%(self.name))
            pass
        def __del__(self):
            print('del方法调用,释放%s内存空间'%(self.name))
            pass
        pass
    cat=Animal('猫')
    print('=================')
    dog=Animal('柯基')
    #由此可看,是当函数彻底执行结束后才释放所有内存空间
    

    在这里插入图片描述
    除此之外,对象被删除的时候也会调用析构方法。

    #析构方法
    class Animal:
        def __init__(self,name):
            self.name=name
            print('init方法调用,初始化%s对象'%(self.name))
            pass
        def __del__(self):
            print('del方法调用,释放%s内存空间'%(self.name))
            pass
        pass
    cat=Animal('猫')
    del cat   #手动删除对象,执行__del__方法
    print('=================')
    dog=Animal('柯基')
    

    在这里插入图片描述
    析构方法主要是用于释放空间,释放后对象就不能再使用。

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

    2.继承

    2.1 单继承

    #单继承
    #父类:
    class Animal:
        def eat(self):
            '''
            父类方法
            :return:
            '''
            print('吃')
            pass
        def drink(self):
            '''
            父类方法
            :return:
            '''
            print('喝')
            pass
        pass
    #子类
    class Dog(Animal):   #继承Animal
        def wwj(self):
            '''
            子类独有的方法
            :return:
            '''
            print('小狗汪汪叫')
        pass
    class Cat(Animal):
        def mmj(self):
            '''
            子类独有的方法
            :return:
            '''
            print('小猫喵喵叫')
            pass
        pass
    d1=Dog()
    d1.eat()
    c1=Cat()
    c1.drink()
    

    在这里插入图片描述

    对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法,极大提高效率,精简代码,便于扩展。

    单继承的语法:
    class 子类名(父类名):
    		.......
    

    2.2 多继承
    子类可以继承多个父类,同时拥有多个父类的公共方法。

    #多继承
    #父类1
    class God:
        def fly(self):
            print('神都会飞')
            pass
        pass
    #父类2
    class Monkey:
        def eat(self):
            print('猴子都吃桃子')
            pass
        pass
    #子类
    class Swk(God,Monkey):   #多继承
        def chan(self):
            print('孙悟空会七十二变')
            pass
        pass
    s=Swk()
    s.chan()
    s.fly()
    s.eat()
    

    在这里插入图片描述
    当多个父类中存在相同的方法时,一层层向上找,就近原则使用。

    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()
    a.eat()
    print(A.__mro__)  #可以显示类的依次继承关系
    

    在这里插入图片描述
    2.3 继承的传递
    孙-子-父

    class Grandfather:
        def eat(self):
            print('爷爷的吃')
            pass
        pass
    class Father(Grandfather):
        pass
    class Son(Father):
        pass
    s=Son()
    print(Son.__mro__)
    s.eat()  #此方法是从父类的父类继承过来的
    #在类的传递过程中,我们把父类称为基类,子类称为派生类,父类的属性喝方法可以一级一级的传到子类,多少级都可以
    

    在这里插入图片描述

    3.重写父类方法

    所谓重写就是在子类中有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法,实际上也就是上述的“就近原则”,这种重写的方法中父类子类的变量什么的都是不互通的。

    但如果一味的重写会使父类继承失去意义,因此如果在子类中重写时可以调用父类方法,提高代码效率。

    4.调用父类方法

    class Dog:
        def __init__(self,name,color):
            self.name=name
            self.color=color
            pass
        def bark(self):
            print('叫')
            pass
        pass
    class keji(Dog):
        def __init__(self,name,color):
            Dog.__init__(self,name,color)   #法一:手动调用调用父类的方法,执行完毕就可以具备name,color这两个实例属性了
            super().__init__(name,color)     #法二:也可以这样调用super是自动找到父类进而调用方法,如果有多个父类会逐一的找直到找到为止
            self.height=20  #如果想要除了父类中的属性之外的属性可以声明
            pass
        def bark(self):
            super().bark()
            print('柯基叫')
            print(self.name)
            pass
        def __str__(self):
            return '{}的颜色是{},它的身高是{}'.format(self.name,self.color,self.height)
        pass
    kj=keji('柯基','黄')
    kj.bark()
    print(kj )
    

    在这里插入图片描述

    注:
    super()自动调用和手动调用写一个就行

    5.多态

    要想实现多态必须遵守两个前提:
    1.继承:多态必须发生在父类和子类之间
    2.重写:子类必须要重写父类的方法
    
    #多态
    class Animal:
        def speak(self):
            print('我是')
        pass
    class Duck(Animal):
        pass
    duck=Duck()
    duck.speak()
    
    #多态
    class Animal:
        def speak(self):
            print('我是')
        pass
    class Duck(Animal):
        def speak(self):
            print('我是一个鸭子')
        pass
    duck=Duck()
    duck.speak()
    

    在这里插入图片描述
    在这里插入图片描述
    以上就是一种多态的体现,同样是duck.speak,输出两个不一样的结果。
    法一:

    #多态
    class Animal:
        def speak(self):
            print('我是')
        pass
    class Duck(Animal):
        def speak(self):
            print('我是一个鸭子')
        pass
    duck=Duck()
    duck.speak()
    class Dog(Animal):
        def speak(self):
            print('我是一只小狗')
            pass
        pass
    dog=Dog()
    dog.speak()
    

    法二:

    #多态
    class Animal:
        def speak(self):
            print('我是')
        pass
    class Duck(Animal):
        def speak(self):
            print('我是一个鸭子')
        pass
    class Dog(Animal):
        def speak(self):
            print('我是一只小狗')
            pass
        pass
    def commonInvoke(obj):
        '''
        统一调用的方法
        :param obj:对象的实例
        :return:
        '''
        obj.speak()
        pass
    listObj=[Duck(),Dog()]
    for i in listObj:
        '''
        循环调用函数
        '''
        commonInvoke(i)
    
    #用一个函数调用
    

    在这里插入图片描述
    以上是多态的第二种体现

    多态的优点:
    增加程序的灵活性
    增加程序的扩展性
    

    6.类属性和实例属性

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

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

    #类属性
    class Student:
        name='黎明'   #类属性
        def __init__(self,age):
            self.age=age   #实例属性
            pass
        pass
    
    lm=Student(18)
    print(lm.name)    #通过实例对象访问类属性
    print(lm.age)
    print('------------')
    print(Student.name)    #通过类对象访问name
    print(Student.age)     #报错是因为age归实例对象所有,不属于类对象
    #只有类属性可以被类对象和实例对象共同访问
    #实例属性只能由实例对象访问
    

    在这里插入图片描述
    所有的实例对象访问的类属性是一个值,实例属性不同。
    实例对象对于类属性只有使用的权力,没有修改的权力。

    #类属性
    class Student:
        name='黎明'   #类属性
        def __init__(self,age):
            self.age=age   #实例属性
            pass
        pass
    
    lm=Student(18)
    print(lm.name)    #通过实例对象访问类属性
    lm.name='修改'     #重新声明一个值
    print(lm.age)
    print(lm.name)    #重新声明后改变了自己
    print('------------')
    xh=Student(22)
    print(xh.name)    #重新声明完后并没有改变
    print('----------------')
    print(Student.name)    #通过类对象访问name
    

    在这里插入图片描述

    #类属性
    class Student:
        name='黎明'   #类属性
        def __init__(self,age):
            self.age=age   #实例属性
            pass
        pass
    Student.name='change'   #这样可以彻底改变类属性的值
    lm=Student(18)
    print(lm.name)    #通过实例对象访问类属性   
    print(lm.age)
    print(lm.name)    #重新声明后改变了自己
    print('------------')
    xh=Student(22)
    print(xh.name)    #重新声明完后并没有改变
    print('----------------')
    print(Student.name)    #通过类对象访问name
    
    

    在这里插入图片描述

    7. 类方法和静态方法

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

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

    在这里插入图片描述
    7.2 静态方法
    类对象所拥有的方法,需要用@staticmethod标识静态方法,静态方法不需要任何参数。

    #类方法
    class People:
        country='china'
        @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
            pass
        pass
    print(People.getData())
    p=People()
    print(p.getData())  #一般情况下,我们不会通过实例对象访问静态方法
    #静态方法的逻辑实现和类、实例对象没什么交互,主要用来存放逻辑性代码,一般不会涉及到类中方法和属性的操作。数据资源能够得到充分利用
    # 返回当前的系统时间:
    import time
    class Time:
        @staticmethod
        def showTime():
            return time.strftime('%H:%M:%S',time.localtime())
        pass
    print(Time.showTime())
    

    7.3 区别

    1.类方法的第一个参数是类对象cls,通过cls引用的类对象的属性和方法,用装饰器@classmethod修饰
    2.实例方法的第一个参数是实例对象self,通过self引用的可能是类属性,也有可能是实例属性,具体问题具体分析,不过存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。
    3.静态方法中不需要额外定义参数,因此在静态方法中引用类属性的化必须通过类对象引用,必须用@staticmethod修饰。
    
  • 相关阅读:
    人工智能第2版学习——盲目搜索1
    C++消息总线Mozart:timer类实现
    Nginx学习(1)—— 下载和安装
    PyQt 小程序
    python数据分析及可视化(六)Pandas的对齐运算、混合运算、统计函数、排序函数、处理缺失值及数据的存储与读取
    认识车载神器-Android Auto
    数据可视化图表库 Apache ECharts
    港科夜闻|国务院发文指出将打造重大科技创新平台,稳步推进粤港澳教育合作,加快与香港科大、中科院共建省实验室...
    项目整合管理
    大数据ClickHouse进阶(一):ClickHouse使用场景和集群安装
  • 原文地址:https://blog.csdn.net/weixin_46081986/article/details/139547033