首页 > 技术文章 > Python面向对象扩展

markshui 2020-05-11 17:17 原文

多态

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

    • 1.封装:屏蔽实现细节,但提供对外调用方式,将功能封装为一个整体,提供简单的调用方式

    • 2.继承:让类与类直接产生父子关系,子类可以拥有父类的方法和属性

    • 3.多态:可以让某个类呈现多种形态

      多态的三个条件

      • 1.必须存在继承关系
      • 2.重写目标方法
      • 3.使用子类对象调用父类方法
      #定义人类:可以跳舞,可以玩,在玩的过程中跳舞
      #实现多态:老年人跳广场舞
      class Person:
          """人的类型"""
      
          def dance(self):
              print("跳舞")
      
          def play(self):
              self.dance()
      
      class OldMan(Person):
          """老年人类型"""
          def dance(self):
              print("跳广场舞")
      
      # per1 = Person()
      # per1.play()
      old = OldMan()
      old.play()
      
  • 用户注册案例

    • 网站可以注册,注册有默认的验证码发送方式

    • 分析

      • 网站类
        • 方法:注册方法,调用默认设备发送验证码
      • 设备类
        • 方法:生成验证码并发送
      class WebSite:
          """网站类型"""
          def register(self,device):
              print("开始注册用户。。。")
              #调用设备发送验证码的方法
              device.send("6666")
              input("验证码已发送,请输入:")
              print("注册成功")
      
      class Device:
          """设备类型"""
          def send(self,code):
              print("默认发送验证码:",code)
      
      #用户注册        
      ws = WebSite()
      device = Device()
      #发起注册
      ws.register(device)
      
    • 实现多态,用不同的设备注册网站,就使用相应的设备发送验证码

      class WebSite:
          """网站类型"""
          def register(self,device):
              print("开始注册用户。。。")
              #调用设备发送验证码的方法
              device.send("6666")
              input("验证码已发送,请输入:")
              print("注册成功")
      
      class Device:
          """设备类型"""
          def send(self,code):
              print("默认发送验证码:",code)
      
      class Phone(Device):
          """手机注册"""
          def send(self,code):
              print("通过手机发送验证码:",code)
      
      class Email:
          """邮箱注册"""
          def send(self, code):
              print("通过邮箱发送验证码:", code)
      
      #用户注册
      ws = WebSite()
      # device = Device()
      phone = Phone()
      #发起注册
      ws.register(phone)
      
      

    实例属性和类型属性

  • 实例属性:在实例对象中定义的属性(在__init__中定义的属性)

  • 类属性:在类中定义的属性(类里面,方法外部),多个实例对象共享一份类属性

  • 实例属性的声明和访问

    (1) 声明

    实例属性的声明,包含在类型的__init__()初始化方法中,使用self关键字将属性绑定在当前对象上

    def __init__(self,name,age):
    	"""实例属性初始化"""
    	self.name = name
    	self.age = age
    

    (2)访问

    实例属性在类型内部可以通过self关键字引用,在类型外部可以通过对象引用变量访问和修改

    class User:
    def __init__(self,name,age):
    	"""实例属性初始化"""
    	self.name = name
    	self.age = age
    user = User("zs",18)
    print(user.name)
    
  • 类属性的声明和访问

    (1)声明

    类里面,方法外部

    #数据类型
    class Data:
        """数据类型"""
        courses_dict = {} #键:课程名称,值:课程对象
    #使用实例对象访问
    data = Data()
    print(data.courses_dict)
    #使用类对象访问
    print(Data.courses_dict)
    

    (2)访问

    类属性能被当前类型的所有对象访问,或者能直接通过类型名称访问

  • 修改

    类属性只能被类名称引用修改,不能通过对象的引用变量修改

    1.不可变类型:对象名.属性名=属性值 给对象添加属性,而不是进行修改

    2.可变类型:如果对象是修改可变类型数据,是真正的修改

    ​ 如果是重新给可变类型变量赋值,则是给对象添加属性

    #数据类型
    class Data:
        """数据类型"""
        # courses_dict = "Python"
        courses_dict = ["Python"]
    
    data = Data()
    #使用类对象修改课程为"java"
    # Data.courses_dict = "java"
    #使用实例对象访问
    # print(data.courses_dict)
    #使用类对象访问
    # print(Data.courses_dict)
    
    #使用实例对象修改课程为 "UI"
    # data.courses_dict = "UI" #实际上是给实例对象增加属性
    #使用实例对象访问
    # print(data.courses_dict)
    #使用类对象访问
    # print(Data.courses_dict)
    
    
    #如果类属性为可变数据类型,则使用实例对象或者类对象都是真正的修改
    # Data.courses_dict.append("java")
    #使用实例对象添加
    # data.courses_dict.append("java")
    #使用实例对象访问
    # print(data.courses_dict)
    #使用类对象访问
    # print(Data.courses_dict)
    
    #实例对象给可变类型重新赋值,则是给该对象添加属性
    data.courses_dict = ["Python","java"]
    #使用实例对象访问
    print(data.courses_dict)
    #使用类对象访问
    print(Data.courses_dict)
    
  • 总结

    类可以调用实例方法,静态方法,类方法和类属性,但是不能调用实例属性

    实例对象可以调用实例方法,类方法,静态方法,类属性,实例属性

    实例对象可以调用所有方法和属性,而类除了不能调用实例属性,其他的方法和属性都可以调用

    class User:
        def __init__(self,name,age):
            """实例属性初始化"""
            self.name = name
            self.age = age
        def introduce(self):
            print(f"我叫{self.name},今年{self.age}岁")
    user = User("zs",18)
    # user.introduce()
    # User.introduce(user)
    print(User.name) #类对象不能调用实例属性
    

静态方法、类方法和实例方法

  • 1、实例方法

    实例方法或者叫对象,指的是在类中定义的普通方法

    只有实例化对象之后才使用的方法,该方法的第一个参数接收的一定是对象本身!

    class User:
        def introduce(self):
            print("这是实例方法中的代码")
    user = User("zs",18)
    #通过对象调用实例方法
    user.introduce()
    
  • 类方法:声明在类的内部,方法上使用装饰器@classmethod

    第一个参数是当前类型本身,约定俗称是cls;类方法执行访问当前类型的类属性,不能访问任何对象的实例属性;类方法被当前类型调用,也能被实例对象调用

    应用场景:当一个方法中只涉及到静态属性的时候可以使用类方法(类方法可以修改类属性)

    class Data:
        student_dic = {}
        
        @classmethod
        def get_student_dic(cls):
            """获取学生信息"""
            return cls.student_dic
        
        @classmethod 
        def set_student_dic(cls,stu_dic):
            cls.student_dic = stu_dic
    
  • 静态方法:是被统一管理在类中的函数,声明在类的内部

    1.格式:在方法添加@staticmethod

    2.参数:静态方法可以有参数,页可以无参数

    3.应用场景:一般用于和类对象以及实例对象无关的代码

    4.使用方式:类名.方法名()(或者对象名.方法名())

    import time
    class Views:
        """界面类型"""
        @staticmethod
        def get_current_time():
            #获取当前时间
            now = time.localtime()
            return time.strftime("%Y-%m-%d %H:%M:%S",now)
    
    print(Views.get_current_time())
    

魔术方法

  • 1.构造方法

    魔术方法 描述
    __new__(cls)方法 创建对象
    __init__(self方法 初始化对象数据
    class User:
        def __init__(self,name,age):
            """实例属性初始化"""
            print("init方法对象初始化")
            self.name = name
            self.age = age
        def __new__(cls, *args, **kwargs):
            print("new方法开始创建对象")
            return object.__new__(cls)
    user = User("zs",18)
    # print(user.name)
    print(user)
    
  • 对象删除方法

    魔术方法 描述
    __del__()方法 对象将要被删除时执行
    class User:
        def __init__(self,name):
            """实例属性初始化"""
            print("init方法对象初始化")
            self.name = name
    
        def __del__(self):
            print("对象将要被删除")
    
    user = User("zs")
    print("代码执行结束")
    
    
    
    class User:
        def __init__(self,name):
            """实例属性初始化"""
            print("init方法对象初始化")
            self.name = name
    
        def __del__(self):
            print("对象将要被删除")
    
    def func():
        user = User("zs")
    func()
    print("代码执行结束")
    
  • 3.对象的打印

    魔术方法 描述
    __str__()方法 打印对象,自定义返回值(字符串)
    __repr__()方法 对象在组合数据类型中,打印展示自定义的返回值
  • 4.对象的函数式调用

    魔术方法 描述
    __call__()方法 让对象可以类似函数的方法直接调用执行
    class User:
        def __call__(self, *args, **kwargs):
            print("我叫张伟强,请多多关照")
    
        def introduce(self):
            print("我叫刘江,请多多关照")
    user= User()
    # user.introduce()
    user()
    
  • 5.其他

    魔术方法 描述
    __eq__()方法 定义==的操作
    class User:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def __eq__(self, other):
            # return self.age==other.age
            return self.__dict__==other.__dict__
        
        def __gt__(self, other):
            return self.age>other.age
        
        def __cmp__(self, other):
            # if self.age>other.age:
            #     return 1
            # elif self.age<other.age:
            #     return -1
            # else:
            #     return 0
    
            return (self.age>other.age)-(self.age<other.age)
    
    user1 = User("刘江",20)
    user2 = User("张伟强",20)
    user3 = User("刘江",20)
    print(user1==user2) #自定义比较年龄
    #自定义比较所有的属性相同,对象才相同
    
    print(user1==user3)
    # == 比较的是值,is比较内存地址
    lst1 = [1,2,3]
    lst2 = [1,2,3]
    print(lst1==lst2)
    print(lst1 is lst2)
    
    • 1.比较两个用户对象的年龄,大于返回True小于返回False
    • 2.比较两个用户对象的年龄,大于返回1,小于返回-1,相同返回0

反射方法

  • 反射:通过字符串的形式操作对象相关的属性 Python中一切事物都是对象(都可以使用反射)

  • 1.反射类的属性和方法 2.反射对象的属性和方法 3.反射模块中的属性和方法

    反射方法 描述
    hasattr(obj,name) 判断是否包含名称为name的属性
    getattr(obj,name) 获取名称为name的属性的具体数据
    setattr(obj,name) 较少 给名称为name属性设置value值
    delattr(obj,name) 较少 删除名称为name的属性
    
    # getattr(obj,name) 获取对象/类中的成员值
    
    # class Teacher:
    #     dic = {"学生信息":"show_student","老师信息":"show_teacher"}
    #
    #     def __init__(self,name,age):
    #         self.name = name
    #         self.age = age
    #
    #     @classmethod
    #     def func(cls):
    #         print("--func--")
    #
    #     def show_student(self):
    #         print("--show_student--")
    #     def show_teacher(self):
    #         print("--show_teacher--")
    
    #反射类中的属性和方法
    #获取Teacher类中的dic
    # print(getattr(Teacher, "dic"))
    #获取Teacher类中的func
    # ret = getattr(Teacher,"func")
    # ret()
    
    
    #反射对象中的属性和方法
    # teacher = Teacher("张老师",30)
    #获取name属性
    # print(getattr(teacher, "name"))
    #获取所有属性
    # print(getattr(teacher,"__dict__"))
    # ret = getattr(teacher,"show_student")
    # ret()
    
    #反射模块中的属性和方法
    import test1
    
    #反射模块中的属性
    # print(getattr(test1,"name"))
    
    #反射模块中的方法
    # func1 = getattr(test1,"func1")
    # func1()
    
    # func2 = getattr(test1,"func2")
    # func2(666)
    
    #反射模块中的类
    # Person = getattr(test1,"Person")
    # per = Person()
    # per.study()
    
    
    
    # hasattr() 检测对象是否有某个成员,返回是布尔值
    
    class Teacher:
        dic = {"学生信息":"show_student","老师信息":"show_teacher"}
    
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        @classmethod
        def func(cls):
            print("--func--")
    
        def show_student(self):
            print("--show_student--")
        def show_teacher(self):
            print("--show_teacher--")
    
    # b = hasattr(Teacher,"dic")
    # if b:
    #     ret = getattr(Teacher,"dic")
    #     print(ret)
    # else:
    #     print("没有当前属性")
    
    #练习:根据用户输入的key来调用对应的方法
    #如:输入"学生信息"-->"--show_student--"
    key = input("请输入学生或者老师信息") #学生信息
    teacher = Teacher("张老师",30)
    b = hasattr(Teacher,teacher.dic.get(key,""))
    if b:
        func = getattr(teacher,teacher.dic[key])
        func()
    else:
        print("此方法不存在")
    

    setattr和getattr

    # setattr() 设置或者添加对象/类中的成员
    
    class Person:
        pass
    #给Person添加静态属性age
    setattr(Person,"age",18)
    print(Person.age)
    
    #delattr 删除对象或者类中的成员
    per1 = Person()
    setattr(per1,"name","张伟强")
    print(per1.name)
    #删除Person类中的age属性
    delattr(Person,"age")
    print(Person.age)
    

单例模式

  • 单例模式确保某一个类只有一个实例存在

  • 当你希望在整个系统中,某个类只能出现一个实例时,就可以使用单例对象

  • 方法:是否是第一次创建对象,如果是首次创建对象,则调用父类__new__()方法创建对象并返回

    ​ 如果不是第一创建对象,直接返回第一次创建的对象即可

    class Shopping:
        instance = None #记录创建的对象,None说明是第一次创建对象
        def __new__(cls, *args, **kwargs):
            #第一次调用new方法,创建对象并记录
            #第2-n次调用new方式时,不创建对象,而是直接放回记录的对象
    
            #判断是否是第一次创建对象
            if cls.instance==None:
                cls.instance = object.__new__(cls)
                return cls.instance
            else: #不是第一次创建对象
                return cls.instance
    
    shop1 = Shopping()
    shop2 = Shopping()
    print(shop1,shop2)
    
    
    class Shopping:
        instance = None #记录创建的对象,None说明是第一次创建对象
        def __new__(cls, *args, **kwargs):
            #第一次调用new方法,创建对象并记录
            #第2-n次调用new方式时,不创建对象,而是直接放回记录的对象
    
            #判断是否是第一次创建对象
            if cls.instance==None:
                cls.instance = object.__new__(cls)
            return cls.instance
    
    shop1 = Shopping()
    shop2 = Shopping()
    print(shop1,shop2)
    

推荐阅读