zoukankan      html  css  js  c++  java
  • 学习python第九天

    1、多态

    面向对象三大特性

    1. 封装 根据 职责 将 属性 和 方法封装 到一个抽象的  中

      • 定义类的准则
    2. 继承实现代码的重用,相同的代码不需要重复的编写

      • 设计类的技巧
      • 子类针对自己特有的需求,编写特定的代码
    3. 多态 不同的 子类对象 调用相同的 父类方法,产生不同的执行结果

      • 多态 可以 增加代码的灵活度
      • 以 继承 和 重写父类方法 为前提
      • 是调用方法的技巧,不会影响到类的内部设计

    1.1  多态案例

    class Dog(object):
        def __init__(self, name):
            self.name = name
        def game(self):
            print("%s 蹦蹦跳跳的玩耍..." % self.name)
    
    class XiaoTianDog(Dog):
        def game(self):
            print("%s 飞到天上去玩耍..." % self.name)
    
    class Person(object):
        def __init__(self, name):
            self.name = name
        def game_with_dog(self, dog):
            print("%s 和 %s 快乐的玩耍..." % (self.name, dog.name))
            # 让狗玩耍
            dog.game()
    
    # 1. 创建一个狗对象
    # wangcai = Dog("旺财")
    wangcai = XiaoTianDog("飞天旺财")
    # 2. 创建一个小明对象
    xiaoming = Person("小明")
    # 3. 让小明调用和狗玩的方法
    xiaoming.game_with_dog(wangcai)

    案例小结

    • Person 类中只需要让 狗对象 调用 game 方法,而不关心具体是 什么狗
      • game 方法是在 Dog 父类中定义的
    • 在程序执行时,传入不同的 狗对象 实参,就会产生不同的执行效果

    2、类属性和类方法

    2.1  类的结构

    术语 —— 实例

    1. 使用面相对象开发,第 1 步 是设计 
    2. 使用 类名() 创建对象,创建对象 的动作有两步:
      • 在内存中为对象 分配空间
      • 调用初始化方法 __init__ 为 对象初始化
    3. 对象创建后,内存 中就有了一个对象的 实实在在 的存在 —— 实例

    结论

    • 每一个对象 都有自己 独立的内存空间保存各自不同的属性
    • 多个对象的方法在内存中只有一份,在调用方法时,需要把对象的引用 传递到方法内部

    类是一个特殊的对象

    • 在程序运行时, 同样 会被加载到内存
    • 在 Python 中, 是一个特殊的对象 —— 类对象
    • 在程序运行时,类对象 在内存中 只有一份,使用 一个类 可以创建出 很多个对象实例
    • 除了封装 实例 的 属性 和 方法外,类对象 还可以拥有自己的 属性 和 方法
      1. 类属性
      2. 类方法
    • 通过 类名. 的方式可以 访问类的属性 或者 调用类的方法

    2.2  类属性和实例属性

    概念和使用

    • 类属性 就是给 类对象 中定义的 属性
    • 通常用来记录 与这个类相关 的特征
    • 类属性 不会用于记录 具体对象的特征
    class Tool(object):
        # 使用赋值语句,定义类属性,记录创建工具对象的总数
        count = 0
        def __init__(self, name):
            self.name = name
            # 针对类属性做一个计数+1
            Tool.count += 1
    
    
    # 创建工具对象
    tool1 = Tool("斧头")
    tool2 = Tool("榔头")
    tool3 = Tool("铁锹")
    # 知道使用 Tool 类到底创建了多少个对象?
    print("现在创建了 %d 个工具" % Tool.count)

    属性的获取机制(科普)

    • 在 Python 中 属性的获取 存在一个 向上查找机制

    • 因此,要访问类属性有两种方式:
      1. 类名.类属性
      2. 对象.类属性 (不推荐,类属性是类的特征,不是对象的特征)

    注意(重点重点!!!)

    • 如果使用 对象.类属性 = 值 赋值语句,只会 给对象添加一个属性,而不会影响到 类属性的值

    2.3  类方法和静态方法

    类方法

    • 类属性 就是针对 类对象 定义的属性
      • 使用 赋值语句 在 class 关键字下方可以定义 类属性
      • 类属性 用于记录 与这个类相关 的特征
    • 类方法 就是针对 类对象 定义的方法
      • 在 类方法 内部可以直接访问 类属性 或者调用其他的 类方法
    @classmethod
    def show_tool_count(cls):
        """显示工具对象的总数"""
        print("工具对象的总数 %d" % cls.count)
    • 类方法需要用 修饰器 @classmethod 来标识,告诉解释器这是一个类方法
    • 类方法的 第一个参数 应该是 cls
      • 由 哪一个类 调用的方法,方法内的 cls 就是 哪一个类的引用
      • 这个参数和 实例方法 的第一个参数是 self 类似
      • 提示 使用其他名称也可以,不过习惯使用 cls
    • 通过 类名. 调用 类方法调用方法时,不需要传递 cls 参数
    • 在方法内部
      • 可以通过 cls.访问类的属性
      • 也可以通过 cls.调用其他的类方法

    静态方法

    • 在开发时,如果需要在  中封装一个方法,这个方法:

      • 既 不需要 访问 实例属性 或者调用 实例方法
      • 也 不需要 访问 类属性 或者调用 类方法
    • 这个时候,可以把这个方法封装成一个 静态方法

    class Dog(object):
        # 狗对象计数
        dog_count = 0
        
        @staticmethod
        def run():
            # 不需要访问实例属性也不需要访问类属性的方法
            print("狗在跑...")
    
        def __init__(self, name):
            self.name = name
    • 静态方法 需要用 修饰器 @staticmethod 来标识,告诉解释器这是一个静态方法
    • 通过 类名. 调用 静态方法

     3、单例设计模式

    • 设计模式

      • 设计模式 是 前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对 某一特定问题 的成熟的解决方案
      • 使用 设计模式 是为了可重用代码、让代码更容易被他人理解、保证代码可靠性
    • 单例设计模式

      • 目的 —— 让  创建的对象,在系统中 只有唯一的一个实例
      • 每一次执行 类名() 返回的对象,内存地址是相同的

    3.1  __new__ 方法

    • 使用 类名() 创建对象时,Python 的解释器 首先 会 调用 __new__ 方法为对象 分配空间
    • __new__ 是一个 由 object 基类提供的 内置的静态方法,主要作用有两个:
      • 在内存中为对象 分配空间
      • 返回 对象的引用
    • Python 的解释器获得对象的 引用 后,将引用作为 第一个参数,传递给 __init__ 方法

    重写 __new__ 方法 的代码非常固定!

    • 重写 __new__ 方法 一定要 return super().__new__(cls)
    • 否则 Python 的解释器 得不到 分配了空间的 对象引用就不会调用对象的初始化方法(所以说是我们在做扩展)
    • 注意:__new__ 是一个静态方法,在调用时需要 主动传递 cls 参数

    3.2  Python 中的单例

     单例 —— 让  创建的对象,在系统中 只有 唯一的一个实例

    1. 定义一个 类属性,初始值是 None,用于记录 单例对象的引用
    2. 重写 __new__ 方法
    3. 如果 类属性is None,调用父类方法分配空间,并在类属性中记录结果
    4. 返回 类属性 中记录的 对象引用
    class MusicPlayer(object):
        # 定义类属性记录单例对象引用
        instance = None
    
        def __new__(cls, *args, **kwargs):
            # 1. 判断类属性是否已经被赋值
            if cls.instance is None:
                cls.instance = super().__new__(cls)
            # 2. 返回类属性的单例引用
            return cls.instance

    只执行一次初始化工作

    • 在每次使用 类名() 创建对象时,Python 的解释器都会自动调用两个方法:
      • __new__ 分配空间
      • __init__ 对象初始化
    • 在上一小节对 __new__ 方法改造之后,每次都会得到 第一次被创建对象的引用
    • 但是:初始化方法还会被再次调用

    解决办法

    1. 定义一个类属性 init_flag 标记是否 执行过初始化动作,初始值为 False
    2. 在 __init__ 方法中,判断 init_flag,如果为 False 就执行初始化动作
    3. 然后将 init_flag 设置为 True
    4. 这样,再次 自动 调用 __init__ 方法时,初始化动作就不会被再次执行 了
    class MusicPlayer(object):
        # 记录第一个被创建对象的引用
        instance = None
        # 记录是否执行过初始化动作
        init_flag = False
    
        def __new__(cls, *args, **kwargs):
            # 1. 判断类属性是否是空对象
            if cls.instance is None:
                # 2. 调用父类的方法,为第一个对象分配空间
                cls.instance = super().__new__(cls)
            # 3. 返回类属性保存的对象引用
            return cls.instance
    
        def __init__(self):
            if not MusicPlayer.init_flag:
                print("初始化音乐播放器")
                MusicPlayer.init_flag = True
    
    # 创建多个对象
    player1 = MusicPlayer()
    print(player1)
    player2 = MusicPlayer()
    print(player2)
  • 相关阅读:
    HDOJ 1025 Constructing Roads In JGShining's Kingdom
    HDOJ 1274 展开字符串
    HDOJ 1503 Advanced Fruits
    Codeforces Round #187 (Div. 2) A,B
    HDOJ 1160 FatMouse's Speed
    HDOJ 1267 下沙的沙子有几粒?
    HDOJ 1224 Free DIY Tour
    山娃向大家问好啦。
    开发系统建议
    打开web全屏
  • 原文地址:https://www.cnblogs.com/tangxlblog/p/9873019.html
Copyright © 2011-2022 走看看