• Python复习笔记(五)面向对象


    1. __init__方法

    # 1. 为对象在内存 中分配空间 -- 创建对象
    # 2. 为对象属性 设置初始值 -- 初始化方法(init)+--------------
    # 3. __init__: 专门用来定义一个类 具有哪些属性的方法!
    class Cat:
        def __init__(self):
            # self.属性名 = 属性的初始值
            self.name = "TOM"
            # print("这是一个初始化方法")
        def eat(self):
            print("%s 吃鱼" % self.name)
    
    # 使用类名()创建对象的时候会自动调用初始化方法__init__        
    tom = Cat()
    print(tom.name)

    TOM 我去了
    TOM

    2. 利用参数设置属性初始值

    # 1. 为对象在内存 中分配空间 -- 创建对象
    # 2. 为对象属性 设置初始值 -- 初始化方法(init)
    # 3. __init__: 专门用来定义一个类 具有哪些属性的方法!
    class Cat:
        def __init__(self, new_name):
            # self.属性名 = 属性的初始值
            self.name = new_name
            # print("这是一个初始化方法")
        def eat(self):
            print("%s 吃鱼" % self.name)
    
    # 使用类名()创建对象的时候会自动调用初始化方法__init__        
    tom = Cat("TOM")
    print(tom.name)
    
    lazy_Cat = Cat("Lazy")
    lazy_Cat.eat()

    3. __del__方法

    class Cat:
        def __init__(self, new_name):
            # self.属性名 = 属性的初始值+
            self.name = new_name
            print("%s 我来了" % self.name)
        def eat(self):
            print("%s 吃鱼" % self.name)
            
        def __del__(self):
            print("%s 我去了" % self.name)
    
    # 使用类名()创建对象的时候会自动调用初始化方法__init__        
    tom = Cat("TOM")
    print(tom.name)
    
    print("-"*50)

    TOM 我来了
    TOM
    --------------------------------------------------

     TOM 我去了

    4. __str__方法

    # -*- coding: utf-8 -*-
    """
    Created on Fri Feb 22 16:35:56 2019
    
    @author: Douzi
    """
    
    class Cat:
        def __init__(self, new_name):
            # self.属性名 = 属性的初始值+
            self.name = new_name
            print("%s 我来了" % self.name)
        def eat(self):
            print("%s 吃鱼" % self.name)
            
        def __del__(self):
            print("%s 我去了" % self.name)
            
        def __str__(self):
            # 必须返回一个字符串
            return "我是小猫[%s]" % self.name
    
    # 使用类名()创建对象的时候会自动调用初始化方法__init__        
    tom = Cat("TOM")
    print(tom)

    TOM 我来了
    我是小猫[TOM]
    TOM 我去了

    5. 身份运算符

    用于 比较 两个对象的 内存地址 是否一致—是否是对同一个对象的引用

    • 在Python中针对 None 比较时,建议使用 is 判断
    • is:例,x is y, 类似 id(x) == id(y))
    • is not:例,x is not y, 类似 id(x) != id(b)

    注意: is: 判断两个对象的引用是否一致; ==:判断两个对象的值是否一样

     

    6. 私有属性和私有方法: __secret

    class Women:
        
        def __init__(self, name):
            
            self.name = name
            self.__age = 18
            
        def __secret(self):
            print("%s 的年龄是 %d" % (self.name, self.__age))
            
        def say(self):
            self.__secret()
            
    xiaofang = Women("小芳")
    
    # 私有属性不能被直接访问
    # print(xiaofang.age)    
    
    # 在对象的方法内部可以访问
    # 私有方法同样不可以在外界方法
    #xiaofang.__secret()
    
    xiaofang.say()

    7. 伪私有属性和私有方法(不推荐使用)

    class Women:
        
        def __init__(self, name):
            
            self.name = name
            self.__age = 18
            
        def __secret(self):
            print("%s 的年龄是 %d" % (self.name, self.__age))
            
        def say(self):
            self.__secret()
            
    xiaofang = Women("小芳")
    
    # 伪私有方法
    print(xiaofang._Women__age)
    xiaofang._Women__secret()

    8. 继承

    8.1 单继承

    8.1.1. 重新实现父类方法

    8.1.2. 调用父类方法: super().funName()

    # -*- coding: utf-8 -*-
    """
    Created on Fri Feb 22 19:23:57 2019
    
    @author: Douzi
    """
    
    class Animal:
        def eat(self):
            print("")
        def drink(self):
            print("")
        def run(self):
            print("")
        def sleep(self):
            print("")
    
    class Dog(Animal):
        
        def bark(self):
            print("www")
        
    
    class XiaoTianQuan(Dog):
        def fly(self):
            print("")
    
        def bark(self):
            print("叫的跟神一样")
            # 使用super(). 调用原本在父类中封装的方法
            super().bark()
            
            # 父类名.方法(self). 调用父类中封装方法
            Dog.bark(self)
    
    
    dog = Dog()
    dog.eat()
    
    xiaotian = XiaoTianQuan()
    xiaotian.bark()
    


    叫的跟神一样
    www
    www

    注意:

    子类对象 不能 在自己方法内部 直接 访问父类的私有属性或私有方法(可以通过父类公共方法访问)

    子类对象 在外界可以访问到父类的公有属性和方法

    8.2 多继承

    概念:子类可以拥有多个父类,并且具有 所有父类 的属性和方法

    class A:
        def test(self):
            print("A class")
    
    class B:
        def demo(self):
            print("B demo")
    
    class C(A, B):
        pass
    
    c = C()
    c.test()
    c.demo()

    注意:父类存在同名属性和方法,少用多继承

    • python中的MRO——方法搜索顺序:主要用于 在多继承时判断方法, 属性 的调用路径
    • python中针对 类 提供一个 内置属性 __mro__ 可以查看方法搜索顺序
    class A:
        def test(self):
            print("A class")
    
        def demo(self):
            print("A Demo")
    
    
    class B:
        def test(self):
            print("B test")
    
        def demo(self):
            print("B demo")
    
    class C(B, A):
        pass
    
    c = C()
    c.test()
    c.demo()
    
    # 确定C类方法调用顺序
    print(C.__mro__)

     8.3 推荐使用新式类 class A(object):

    9. 多态

    9.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("旺财")
    xiaotian = XiaoTianDog("飞天狗")
    
    
    # 2. 创建一个小明对像
    xiaoming = Person("小明")
    
    # 3. 让小明调用和狗玩
    # xiaoming.game_with_dog(wangcai)
    xiaoming.game_with_dog(xiaotian)
    • person 类中只需要让 狗对象 调用game方法,而不关心具体 什么狗
    • game方法是在Dog父类中定义的
    • 在程序执行时,传入不同的 狗对象 实参,就会产生不同的执行效果

    10. 几个注意

    10.1 类是一个特殊的对象

    • 在运行时候, 同样会被 加载到内存
    • 类对象 在内存中 只有一份,使用一个类 可以创建出 很多个对象实例
    • 类对象 还可以拥有自己 的属性 和 方法
    1. 类属性
    2. 类方法

    通过 类名,可以访问类的属性。

    11. 类属性

    • 类属性 就是给 类对象 中 定义的 属性
    • 通常用来记录 与这个类相关 的特征
    • 类属性 不会用于 记录 具体对象的特征

    示例需求

    • 定义一个工具类
    • 每个工具都有自己的name
    • 需要知道有多少工具

    访问类属性两种方式:

    1. 类名.类属性

    2. 对象.类属性(不推荐)

    class Tool(object):
    
        # 使用赋值语句定义 类属性,记录所有工具对象大数量
        count = 0
    
        def __init__(self, name):
            self.name = name
    
            Tool.count += 1
    
    tool1 = Tool("斧子")
    tool1 = Tool("水桶")
    
    print(Tool.count)

    2

    12. 类方法

    • 类方法 就是针对 类对象 定义的方法
    • 在 类方法 内部 可以直接访问 类属性 或者调用其他的 类方法

    语法如下;

    @classmethod 
    def 类方法名(cls):
        pass

    修饰器 @classmethod 来标识,告诉解释器 这是一个类方法

    • 类方法 第一个参数 应该是 cls
      • 哪一个类 调用的方法,方法内的 cls就是 哪一个类的引用
      • 这个参数 和 实例方法 的 第一参数 是 self 类似
      • 提示 使用其他名称也可以,不过习惯使用 cls
    • 通过 类名。调用 类方法,调用方法时,不需要传递 cls 参数
    • 在方法内部:
      • 可以通过 cls,访问 类的属性
      • 也可以通过 cls,调用 其他类方法
    class Tool(object):
    
        # 使用赋值语句定义 类属性,记录所有工具对象大数量
        count = 0
    
        @classmethod
        def show_tool_count(cls):
            print("工具对象的数量 %d" % cls.count)
    
        def __init__(self, name):
            self.name = name
    
            Tool.count += 1
    
    # 创建工具对象
    tool1 = Tool("")
    tool2 = Tool("斧子")
    
    #调用类方法
    Tool.show_tool_count()

     综合

    class Tool(object):
    
        # 使用赋值语句定义 类属性,记录所有工具对象大数量
        count = 0
    
        @classmethod
        def show_tool_count(cls):
            print("工具对象的数量 %d" % cls.count)
    
        def __init__(self, name):
            self.name = name
    
            Tool.count += 1
    
    # 创建工具对象
    tool1 = Tool("")
    tool2 = Tool("斧子")
    
    #调用类方法
    Tool.show_tool_count()

    13. 单例

    目的:让类创建的对象,在系统中 只有 唯一的一个实例

    13.1 __new__方法

    • 使用 类名() 创建对象时,Python会先调用 __new__方法为对象 分配空间

    • __new__ 是一个由 Object 基类提供的 内置静态方法,作用:

      • 在内存中为对象分配空间

      • 返回对象的引用

    • Python的解释器获得对象的引用后,将引用作为第一个参数,传递给 __init__方法

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

    • 重写__new__方法 一定要 return super().__new__(cls)

    • 否则 Python解释器 得不到 分配了空间的 对象引用,就不会调用对象的初始化方法

    • 注意: __new__是一个静态方法,在调用时候:主动传递 cls 参数

    class MusicPlayer(object):
    
        def __new__(cls, *args, **kwargs):
            # 1. 创建对象时候,new方法会被自动调用
            print("创建对像,分配空间")
            
            # 2. 为对象分配空间, 返回对象引用
            return super().__new__(cls)
    
        def __init__(self):
            print("播放器初始化")
    
    player = MusicPlayer()
    
    print(player)

    13.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:
                # 2. 调用父类大方法,为第一个对像分配空间
                cls.instance = super().__new__(cls)
            # 3. 返回类属性保存大对象引用
            return cls.instance
    
    player1 = MusicPlayer()
    print(player1)
    player2 = MusicPlayer()
    print(player2)

    只执行一次初始化工作

    在每次使用 类名() 创建对象时, Python 的解释器都会自动调用两个方法:

    • __new__:分配空间
    • __init__:对象初始化

    虽然对 __new__ 方法改造后,每次都会得到 第一次被创建对象的引用

    但是:初始化方法还是会被再次调用!

    class MusicPlayer(object):
    
        # 类属性:记录第一个被创建对像大引用
        instance = None
    
        def __new__(cls, *args, **kwargs):
            # 1. 判断类属性啥是否为空对像
            if cls.instance is None:
                # 2. 调用父类大方法,为第一个对像分配空间
                cls.instance = super().__new__(cls)
            # 3. 返回类属性保存大对象引用
            return cls.instance
    
        def __init__(self):
            print("初始化播放器")
    
    player1 = MusicPlayer()
    print(player1)
    player2 = MusicPlayer()
    print(player2)

     

    需求

    • 让初始化动作 只被执行一次
    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):
    
            # 1. 判断是否执行初始化动作
            if MusicPlayer.init_flag:
                return
    
            # 2. 如果没有,在执行初始化动作
            print("初始化播放器")
    
            MusicPlayer.init_flag = True
    
    player1 = MusicPlayer()
    print(player1)
    player2 = MusicPlayer()
    print(player2)

    14. 异常

    14.1 语法

    try:
        num = int(input("输入整数"))
    except:
        print("输入正确数字")
    

    14.2 错误类型捕获

    完整语法:

    try:
        pass
    except 错误类型1:
        pass
    except 错误类型2:
        pass
    except (错误类型3, 错误类型4):
        pass
    except Exception as result:
        print(result)
    else:
        # 没有异常才会执行的
        pass
    finally:
        print("无论是否有异常都会执行的代码")

    例子:

    try:
        num = int(input("输入:"))
        result = 8 / num
        print(result)
    except ZeroDivisionError:
        print("除0错误")
    except ValueError:
        print("请输入正确整数")
    try:
        num = int(input("输入:"))
        result = 8 / num
        print(result)
    # except ZeroDivisionError:
    #     print("除0错误")
    except ValueError:
        print("请输入正确整数")
    except Exception as result:
        print("未知错误 %s" % result)

    输入:0
    未知错误 division by zero

    14.3 异常的传递

    • 当函数/方法 执行 出现异常,将异常传递 给 函数/方法的 调用一方
    • 如果 传递到主程序,仍然 没有异常处理,程序才会被终止

    提示:

    • 在开发中,可以在主函数中增加 异常捕获

    • 而在主函数中调用的其他函数,只要出现异常,都会传递到主函数的 异常捕获

    • 这样就不要在代码中,增加大量的 异常捕获

    def demo1():
        return  int(input("输入:"))
    
    def demo2():
        return demo1()
    
    try:
        num = demo2()
        result = 8 / num
        print(result)
    # except ZeroDivisionError:
    #     print("除0错误")
    except ValueError:
        print("请输入正确整数")
    except Exception as result:
        print("未知错误 %s" % result)
    else:
        print("尝试成功")
    finally:
        print("无论是否错误都会执行的代码")
    
    print("-"*50)

    14.4 抛出 raise 异常

    • 创建一个 Exception 对象

    • 使用 raise 关键字 抛出 异常对象

    def input_password():
        pwd = input("输入密码: ")
    
        if len(pwd) >= 8:
            return pwd
    
        print("主动抛出异常")
        # 1. 创建异常对象
        ex = Exception("密码长度不够")
        # 2. 主动抛出异常
        raise ex
    
    try:
        print(input_password())
    except Exception as result:
        print(result)

    15. 模块

    import hm_01_import1 as im01
    import hm_01_import2 as im02
    
    im01.say_fuck()
    im02.say_hello()

    15.1 导入部分工具(可直接使用模块内容)

    from...import 导入

    两个模块有相同函数,会使用后导入模块的函数

    15.2 导入顺序

    • 搜索 当前目录 指定模块名 的文件,如果有就直接导入

    • 如果没有,再搜索 系统目录

    • 模块.__file__:可以查看文件位置

    15.3 __name__属性

    文件被导入时,能够直接执行的代码不需要被执行

    hm_09__name__模块.py

    def say_hello():
        print("小明,hello")
    
    if __name__ == "__main__":
        print(__name__)
    
        print("小明开发的模块")
        say_hello()

    __main__
    小明开发的模块
    小明,hello

    hm_09__name__测试导入.py

    import hm_09__name__模块
    
    print("这是本程序的代码")
    

    hm_09__name__测试导入.py

    注意:如果hm_09__name__模块.py 文件不加 if __name__ == "__main__": ,则在hm_09__name__测试导入.py文件中会输出

    所以很多Python文件中看到以下格式代码

    既可以执行,也可以当做模块导入

    # 导入模块
    # 定义全局变量
    # 定义类
    # 定义函数
    
    def main():
        # ...
        pass
    
    if __name__ == '__main__':
        main()

    16. 包(package)

    • 包是一个 包含多个模块的 特殊目录
    • 目录下有一个 特殊文件 __init__.py
    • 包名的 命名方式 和变量名一致,小写字母+ _

    案例演练

    1. 新疆一个 dz_message的

    2. 新建两个Python文件

    3. 在外部直接导入 dz_message 的包

    __init__.py

    要在外界使用包的模块中,需要在 __init__.py 中指定对外界提供的模块列表

    from . import send_message
    from . import receive_message

    导入包的模块

    import cn.Douzi.dz_message as dz_message
    
    dz_message.send_message.send("Douzi is Cute")
    
    txt = dz_message.receive_message.receive()
    print(txt)

    17. 制作发布压缩包

    17.1 创建setup.py

    from distutils.core import setup
    
    setup()
    setup(name="hm_message",                         # 包名
          version="1.0",
          description="Douzi's 发送和接受消息模块",
          long_description="完整的发送和接受消息模块",   # 完整描述信息
          author="Douzi",                            # 作者
          url="www.cnblogs.com/douzujun/",           # 主页
          py_modules=["dz_message.send_message",
                      "dz_message.receive_message"])

    17.2 构建模块

    python3 setup.py build

    17.3 生成发布压缩包

    python3 setup.py sdist

    18. 安装模块

    sudo python3 setup.py install

  • 相关阅读:
    PHP函数include include_once require和require_once的区别
    PHP替换回车换行的三种方法
    PHP获取绝对路径dirname(__FILE__)和__DIR__比较
    jQuery实现倒计时重新发送短信验证码功能示例
    js人民币转大写
    js前端数据验证JS工具
    安卓动画学习笔记
    ActivityNotFoundException: No Activity found to handle Intent
    Android笔记
    再次踩bug:遍历删除list(java.util.ConcurrentModificationException)
  • 原文地址:https://www.cnblogs.com/douzujun/p/10420297.html
Copyright © 2020-2023  润新知