Python多态

多态

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

    • 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)
    
  • 工厂模式

工厂模式是一个在软件开发中用来创建对象的设计模式。

当程序运行输入一个“类型”的时候,需要创建于此相应的对象。这就用到了工厂模式。

在如此情形中,实现代码基于工厂模式,可以达到可扩展,可维护的代 码。当增加一个新的类型,不在需要修改已存在的类,只增加能够产生新类型的子类。

代码实现:

class Car(object):
    def run(self):
        print("吧里吧里的跑。。。")

    def stop(self):
        print("蹭蹭的停车。。。")


class BMW(Car):
    def run(self):
        print("宝马-->>>吧里吧里的跑。。。")

    def stop(self):
        print("宝马-->>>蹭蹭的停车。。。")


class Benz(Car):
    def run(self):
        print('奔驰-->>>吧里吧里的跑...')

    def stop(self):
        print('奔驰-->>>蹭蹭的停车...')


class Skoda(Car):
    def run(self):
        print("斯柯达-->>>吧里吧里的跑。。。")

    def stop(self):
        print("斯柯达-->>>蹭蹭的停车。。。")


class CarFactory(object):
    def new_car(self, name):
        if name == "BMW":
            bmw = BMW()
        if name == 'Benz':
            benz = Benz()
            return benz
        if name == 'skd':
            return Skoda()


class CarStore(object):

    def __init__(self, factory):
        self.factory = factory

    def order(self, name):
        new_car = self.factory.new_car(name)
        return new_car


car_factory = CarFactory()
car_store = CarStore(car_factory)
car = car_store.order('skd')
car.run()
car.stop()
  • 策略模式

策略指的就是为了达到某一目的而采取的多种手段或者方法。

为了实现软件设计,对象可能会用到多种多样的算法(逻辑)。这些算法甚至会经 常改变。如果将这些算法都硬编码到对象中,将会使得对象本身变得臃肿不堪, 策略模式很好的实现了将算法与本身对象解耦,从而避免出现上述的问题。

因此策略模式可以定义为: 定义一系列算法(逻辑),将每一个算法封装起来(一 个算法创建一个类),并让它们可以相互替换。此模式让算法的变化,不会影响到 使用算法的客户

策略模式包含以下 3 个角色:

Context(环境类)

Strategy(抽象策略类)

ConcreteStrategy(具体策略类)

在这里插入图片描述

练习 1:假设某司维护着一些客户资料,需要在该司有新产品上市或者举行新活 动时通知客户。现通知客户的方式有两种:短信通知、邮件通知。应如何设计该 系统的客户通知部分?为解决该问题,我们先构造客户类,包括客户常用的联系 方式和基本信息,同时也包括要发送的内容。

代码实现:

# 发送方式 -- 父类
class MsgSender(object):
    dst_code = ''  # 联系方式
    info = ''  # 发送方式

    # 发送内容
    def send(self):
        pass


# 具体发送方式-->子类
class EmailSender(MsgSender):
    def send(self):
        print("邮件给{}发送内容:{}".format(self.dst_code, self.info))


class PhoneSender(MsgSender):
    def send(self):
        print('打电话给{}发送内容:{}'.format(self.dst_code, self.info))


# 用户

class Customer(object):
    name = ''
    phone = ''
    email = ''
    send_way = None  # 发送方式

    def set_send_way(self, send_way):
        self.send_way = send_way

    def send_msg(self):
        self.send_way.send()


if __name__ == '__main__':
    # 创建用户
    customer = Customer()
    customer.email = '3501976639@qq.com'
    customer.phone = '17673277948'
    customer.name = 'zsc'

    # 创建邮箱发送方式
    email_sender = EmailSender()
    email_sender.info = '欢迎看新产品'
    email_sender.dst_code = customer.email

    customer.set_send_way(email_sender)
    customer.send_msg()

    # 打电话
    phone_sender = PhoneSender()
    phone_sender.dst_code = Customer.phone
    phone_sender.info = '欢迎看新产品'
    customer.set_send_way(phone_sender)
    customer.send_msg()
  • 观察者模式

观察者模式:又叫发布订阅模式,定义了一种一对多的依赖关系,让多个观察者 对象同时监听某一个主题对象,这个主题对象的状态发生变化时,会通知所有观 察者对象,是他们能自动更新自己

具体应用场景: 事件驱动系统是观察者模式的例子。在这种系统中,监听者被用于监听特定事件。 监听者正在监听的事件被创建出来时,就会触发它们。这个事件可以是键入(键 盘的)某个特定键、移动鼠标或者其他。事件扮演发布者的角色,监听者则扮演 观察者的角色。在这里,关键点是单个事件(发布者)可以关联多个监听者(观 察者)

代码实现:

# 主题-->通知者 -->班长
class Monitor(object):
    def __init__(self):
        self.observers = []  # 保存所有观察者对象
        self.status = ''  # 表示状态

    def attach(self, observer):
        """绑定每一个观察者"""
        self.observers.append(observer)

    def notify(self):
        """通知每一个观察者"""
        for observer in self.observers:
            observer.update()


# 观察者--> 睡觉的同学
class SleepStudentObserver(object):
    def __init__(self, name, monitor):
        self.name = name
        self.monitor = monitor  # 绑定通知者

    def update(self):
        print('{},{}赶快起来学习吧'.format(self.monitor.status, self.name))


if __name__ == '__main__':
    monitor = Monitor()
    observer1 = SleepStudentObserver('zs', monitor)
    observer2 = SleepStudentObserver('lyc', monitor)
    monitor.attach(observer1)
    monitor.attach(observer2)
    monitor.status = '老师又来了'
    monitor.notify()
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值