• 13-多态


    多态

    • 面向对象特征

      • 封装:用类将属性和方法封装在一起,配合私有属性和私有方法使用

      • 继承:让子类可以继承父类的属性和方法,不包括私有的,子类可以扩展自己的属性和方法

        • 1.子类完全继承父类的所有属性和方法的情况,如:动物类,狗类,动物类作为父类,狗类作为子类,一般有从属关系
        • 2.如果父类中有部分属性和方法不继承,则需要将它们的公共的属性和方法抽取出来作为父类,如:狗类和猫类,将狗和猫的公共属性和方法提取出来作为父类
      • 多态(了解):在继承的基础上,而且需要用重写。要在父类中定义一个方法,让所有子类重写该方法,那么我们可以使用父类对象去指向不同的子类来调用同一个方法名,则有不同的状态或结果(animal看作是父类对象,Python没有真正的多态,这里将animal看作是父类的对象)

        • # 父类
          class Animal:
              def bark(self):
                  pass
          
          # 子类
          class Dog(Animal):
              def bark(self):
                  print('汪汪汪的叫')
          
          class Cat(Animal):
              def bark(self):
                  print('喵喵喵的叫')
          
          class Wolf(Animal):
              def bark(self):
                  print('嗷嗷嗷的叫')
          
          class Person:
              def __init__(self, name):
                  self.name = name
              def beat_animal(self, animal):
                  print(f'{self.name}正在殴打小动物')
                  animal.bark()  # animal看作是父类对象,Python没有真正的多态,这里将animal看作是父类的对象
          
          # 对象
          dog = Dog()
          cat = Cat()
          wolf = Wolf()
          xiaoming = Person('黄晓明')
          xiaoming.beat_animal(dog)  # 调用小明,将动物子类的对象作为参数传递至对应的方法中
          
      • 抽象

    获取对象信息

    • type():判断数据类型
    • isinstance():判断某个对象是否属于指定的类的对象,指定的类的对象可以是一个元组
    • dir():列出指定对象中所包含的所有的内容【成员变量/对象属性,成员方法】
      • dir() # 获得当前模块的属性列表
      • dir([ ]) # 查看列表的方法

    类属性&类方法

    • 如果类属性的值是引用类型,则该类属性会被当前类创建的所有对象共享;如果该引用类型属性值是成员属性,则不会共享

      • class Person:
            # 类属性(类变量)
            name = '鹿晗'
            age = 10
            # 如果类属性的值是引用类型,则该类属性会被当前类创建的所有对象共享
            likes = ['关晓彤', '舒淇']
            
            def __init__(self, age):  # 在构造函数中初始化对象属性/成员变量
                # 对象属性(成员变量)
                self.age = age
                # 不会共享
                self.likes2 = ['关晓彤', '舒淇']  # 对象属性直接写死,不需要在构造函数中写出来
        
    • 对象属性如果直接给出初始值写死,则不需要在构造函数中写出来进行初始化

    • 对象.类属性/类.类属性/对象.对象属性

    • 针对相同名称的类属性和对象属性,对象调用会优先调用对象属性

    • 可以对对象属性和类属性进行修改

    单例模式

    • 让类只能创建出一个对象

    • 设计模式:一种解决问题的方式

    • 设计模式:23种设计模式,比如:单例模式,工厂模式,代理模式,装饰器模式,适配器模式

    • 使用new方法

      • class Person:
            # 构造函数:用来对属性初始化
            def __init__(self):
                print('__init__')
        
            # 类属性
            instance = None
            
            # new方法:用来创建对象
            @classmethod
            def __new__(cls, *args, **kwargs):  # 自动先调用new, 重写new
                print('__new__')  # __new__
                if not cls.instance:
                    print('---创建新对象---')
                    cls.instance = super(Person, cls).__new__(*args, **kwargs)  # 新建对象,相当于修改类属性.Person是父类,父类对应cls(特殊形参)
                    # cls.instance = object.__new__(cls)  # object可以换成super()
                return cls.instance
        
        # 对象
        p = Person()
        p2 = Person()
        print(p == p2)  # True
        
        • 初始化一个类属性并使其值为None
        • 利用类方法重写创建对象的方法:new方法
        • 隐式调用类的new方法来新建对象,并赋值给初始化的类属性,相当于修改类属性
    • 使用装饰器

      • # 装饰器
        def outer(cls):
            instance = None
            print('instance初始化为None')
            def inner(*args, **kwargs):  # 通用装饰器
                nonlocal instance
                if not instance:
                    print('---创建了新的对象---')
                    instance = cls(*args, **kwargs)  # cls相当于Person类, 新建对象
                print('---返回对象---')
                return instance
            return inner
        
        @outer  # 加上装饰器的一瞬间调用一次instance = None,后面不会再调用
        class Person:
            pass
        
        p1 = Person()
        p2 = Person()
        print(p1 is p2)  # True
        
        • 加上装饰器的一瞬间调用一次在外函数初始化值为None的变量,后面构建对象时,直接用的是内函数
    • 使用类方法

      • # 使用类方法
        class Singleton:
            instance = None
        
            @classmethod
            def get_instance(cls):
                if not cls.instance:
                    cls.instance = cls()  # 相当于修改类的属性,cls()相当于Singleton()
                return cls.instance
        
        s1 = Singleton.get_instance()  # 通过调用类方法新建对象
        s2 = Singleton.get_instance()
        print(s1 is s2)  # True
        
        • 在创建对象时调用类方法进行新建

    生产者消费者模式

    • 如果一个线程的运行是根据另一个线程的结果,那么需要使用生产者和消费者模式

    • import time
      from threading import Thread
      import queue
      
      q = queue.Queue()
      
      def make():
          num = 1
          while True:
              print(f'做了{num}个包子')
              q.put(num)
              num += 1
              time.sleep(1)
      
      def eat():
          while True:
              num = q.get()
              print(f'吃了{num}个包子')
      
      if __name__ == '__main__':
          t1 = Thread(target=make)
          t2 = Thread(target=eat)
          t1.start()
          t2.start()
          t1.join()
          t2.join()
      

    类方法和静态方法

    • class Person:
          # 构造方法
          def __init__(self, name):
              self.name = name
      
          # 成员方法(常用)
          def sleep(self):
              print('睡觉', self)
      
          # 私有方法
          def __run(self):
              print('跑步')
      
          # 类方法
          # 1.可以使用类和对象调用,但是建议使用类来调用,可以节省内存
          # 2.可以使用类属性和其他类方法,但是不能使用对象属性和成员方法和私有方法
          # 3.一般用在功能比较独立、和类中其他属性和方法无关的情况下
          # cls: class
          @classmethod
          def eat(cls):
              print('吃饭:', cls==Person)  # 在类方法中不能使用对象属性和成员方法,因为没有self
      
          # 静态方法
          # 1.可以使用类和对象调用,但是建议使用类来调用,可以节省内存
          # 2.不可以使用对象属性和成员方法和私有方法,一般也不用类属性和类方法
          # 3.就是一个非常普通的函数,只是写在类里面
          @staticmethod
          def sing():
              print('唱歌')
      
      # 对象
      p = Person('蔡徐坤')
      Person.eat()  # 类.类方法  # 吃饭: True(类是不占内存的)
      p.eat()  # 对象.类方法 # 吃饭: True
      Person.sleep(p)  # 睡觉,类.成员方法(不推荐,尽量不这么用)
      p.sleep()  # 睡觉,对象.成员方法
      
      Person.sing()  # 唱歌,类.静态方法,推荐
      p.sing()  # 唱歌,对象.静态方法
      
      • 类方法@classmethod
        • 1.可以使用类和对象调用,但是建议使用类来调用,可以节省内存
        • 2.可以使用类属性和其他类方法,但是不能使用对象属性和成员方法和私有方法
        • 3.一般用在功能比较独立、和类中其他属性和方法无关的情况下
      • 静态方法@staticmethod
        • 1.可以使用类和对象调用,但是建议使用类来调用,可以节省内存
        • 2.不可以使用对象属性和成员方法和私有方法,一般也不用类属性和类方法
        • 3.就是一个非常普通的函数,只是写在类里面
      • 类.类方法/对象.类方法/类.成员方法(不推荐,需要传入对象)/对象.成员方法/类.静态方法/对象.静态方法

    动态添加属性和方法

    • 动态添加的属性:只存在于当前的对象中

    • 动态添加方法

      • 需要传入对象

      • class Person:
            age = 20
            def __init__(self, name):
                self.name = name
        
        # 对象
        p = Person('成龙')
        print(p.name)  # '成龙'
        
        # 动态添加属性:只存在于当前的对象中
        p.age = 10
        print(p.name, p.age, Person.age)  # 成龙 10 20
        # print(Person('李小龙').age)  # 报错
        
        # 动态添加方法:了解
        def sleep(self):
        	print(self.name, '在睡觉')
            
        p.sleep2 = sleep
        p.sleep2(p)  # 调用, 成龙 在睡觉
        
        from types import MethodType
        
        def sleep(self):
            print(self.name, '在睡觉')
        
        p.sleep3 = MethodType(sleep, p)
        p.sleep3()  # 调用, 成龙 在睡觉
        
        # 类属性赋值要使用类.类属性的方式赋值
        # 每个对象的对象属性是独立的内存
        

    特殊属性

    • 类.__name__ # 类
    • 对象.__class__ # __main__.类
    • 对象.__dict__ # 快速获取对象的所有属性及其属性值
    • 对象.__module__ # __main__
    • 类.__module__ # __main__
    • 类.__bases__ # 父类
    • 类.__mro__ # 查看某个类的继承顺序
    • print(__name__) # __main__

    运算符重载

    • class Girl:
          def __init__(self, name, age):
              self.name = name
              self.age = age
      
          # 加法
          def __add__(self, other):  # 重写运算符方法
              return self.age + other.age
      
      # 对象
      p1 = Girl('杨超越', 22)
      p2 = Girl('关晓彤', 20)
      print(p1.age + p2.age) # 42
      print(p1 + p2)  # 42
      
      • 让类可以使用运算符
      • 相当于重写内部的运算符方法
  • 相关阅读:
    redis学习
    Ubuntu命令大全
    关于jquery中attr和prop的用法
    Ubuntu下修改为永久DNS的方法
    Yii2 behaviors中verbs access的一些理解
    vue_ form表单 v-model
    vue-one_demo_music
    ES6
    VUE 入门 01
    Django model.py表单设置默认值允许为空
  • 原文地址:https://www.cnblogs.com/lotuslaw/p/14008863.html
Copyright © 2020-2023  润新知