python进阶篇-day02-面向对象高级

day19-面向对象高级和应用 文章摘要: 本文深入探讨Python面向对象编程的高级特性,重点解析继承、异常处理与反射机制。内容包括:继承补充(mro和c3算法解析)、内置函数补充、异常处理机制及反射应用。通过多继承示例和mro()方法详细展示类成员查找顺序,并对比Python2与Python3在经典类和新式类上的区别。最后介绍异常处理的基本语法和自定义异常,以及反射机制的常见应用场景。掌握这些知识可提升代码重用性、健壮性和灵活性,是Python高级编程的重要技能。 关键词:Python、面向对象、继承、异常处理、反射 阅读详情

day02面向对象高级

 

 

定义类的方法

class Student:
class Student():
class Student(object):  object => 父类名, object为所有类的父类, 顶级类

 

 

 

一. 继承

单继承

介绍

概述

实际开发中, 我们发现好多类中的部分内容是相似的, 或者相同的, 每次写很麻烦, 针对于这种情况, 我们可以把这些相似(想同)的部分抽取出来,单独的放到1个类中(父类), 然后让那多个类(子类) 和这个类产生关系, 这个关系就叫: 继承.

子承父业, Python中的继承, 子类 => 继承父类的 属性, 行为.

格式

class 子类名(父类名):
    pass

好处

  1. 提高代码的复用性.

  2. 提高代码的可维护性.

弊端

耦合性增强了. 父类"不好"的内容, 子类想没有都不行.耦合: 指的是类与类之间的关系.

别名

子类: 也叫 派生类, 扩展类.父类: 也叫 基类, 超类.

细节

所有的类都直接或者间接继承自object, 它是所有类的父类, 也叫: 顶级类.

代码演示

# 案例: 父类有默认性别男, 爱好散步行走, 定义子类继承父类, 看是否可以访问这些属性 和 行为.
# 1. 定义父类.
class Father:
    # 1.1 定义父类的属性.
    def __init__(self):
        self.gender = '男'
​
    # 1.2 定义父类的行为
    def walk(self):
        print('饭后走一走, 能活九十九!')
​
# 2. 定义子类, 继承自父类.
class Son(Father):
    pass
​
# 在main中测试
if __name__ == '__main__':
    # 3. 创建子类的对象.
    s = Son()
    # 4. 尝试打印 s对象的 属性 和 行为
    print(f'性别: {s.gender}')
    s.walk()

案例

故事1

一个摊煎饼的老师傅,在煎饼果子界摸爬滚打多年,研发了一套精湛的摊煎饼技术, 师父要把这套技术传授给他的唯一的最得意的徒弟。

代码

# 1. 创建1个师傅类, 充当父类.
class Master(object):
    # 1.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'
​
    # 1.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
​
# 2. 定义徒弟类, 继承自师傅类.
class Prentice(Master):
    pass
​
​
# 在main函数中测试
if __name__ == '__main__':
    # 3. 创建子类的对象
    p = Prentice()
    # 4. 尝试打印 p对象的 属性 和 行为
    print(f'从父类继承的属性: {p.kongfu}')
    p.make_cake()  # 从父类继承来的行为.

 

 

多继承

介绍

  1. Python中支持多继承写法, 即: 1个类可以有多个父类, 写法为: class 子类名(父类名1, 父类名2...)

  2. 多继承关系中, 子类可以继承所有父类的属性和行为. 前提: 父类的私有成员除外(__方法或属性).

  3. 多继承关系中, 多个父类如果有重名属性或者方法时, 子类会优先使用第1个父类(即: 最前边的父类)的该成员.

  4. 上述的继承关系, 我们可以通过 Python内置的 mro属性 或者 mro()方法来查看.mro: => Method Resolution Order, 即: 方法的解析顺序(调用顺序)

案例

故事2

小明是个爱学习的好孩子,想学习更多的摊煎饼果子技术,于是,在百度搜索学校,报班来培训学习摊煎饼果子技术。

代码

# 1. 创建1个师傅类, 充当父类.
class Master(object):
    # 1.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'
        self.name = 'Master'
​
    # 1.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
# 2. 创建1个师傅类, 充当父类.
class School(object):
    # 2.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[AI煎饼果子配方]'
​
    # 2.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
# 3. 定义徒弟类, 继承自师傅类.
class Prentice(School, Master):
    pass
​
​
# 在main函数中测试
if __name__ == '__main__':
    # 4. 创建子类的对象
    p = Prentice()
    # 5. 尝试打印 p对象的 属性 和 行为
    print(f'从父类继承的属性: {p.kongfu}')
    p.make_cake()  # 从父类继承来的行为.
    print('-' * 21)
​
    # 6. 演示方法的解析顺序, 即: MRO, 看看方法优先会从哪些类中找.
    print(Prentice.__mro__)     # 输出: Prentice >  School > Master > object, 封装成: 元组
    print(Prentice.mro())       # 输出: Prentice >  School > Master > object, 封装成: 列表

 

 

方法重写

介绍

概述: 子类出现和父类重名的属性, 方法时, 会覆盖父类中的成员, 这种写法就称之为: 重写, 也叫: 覆盖.注意: 重写一般特指: 方法重写.应用场景: 当子类需要沿袭父类的功能, 而功能主体又有自己额外需求的时候, 就可以考虑使用方法重写了.

细节: 1. 子类有和父类重名的属性和方法时, 优先使用 子类的成员. 就近原则.

  1. 重写后, 子类如何访问父类的成员呢

    格式1: 父类名.父类方法名(self)格式2: super().父类方法()

案例

故事3

小明掌握了老师傅和的技术后, 子级潜心钻研出一套自己的独门配方的全新煎饼果子配方.

代码

# 1. 创建1个师傅类, 充当父类.
class Master(object):
    # 1.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'
        self.name = 'Master'
​
    # 1.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
# 2. 创建1个师傅类, 充当父类.
class School(object):
    # 2.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[AI煎饼果子配方]'
​
    # 2.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
# 3. 定义徒弟类, 继承自师傅类.
class Prentice(School, Master):
    # 3.1 定义本类(子类)的 属性.
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'
​
    # 3.2 定义本类(子类)的 行为, 表示: 摊煎饼.
    def make_cake(self):        # 子类出现和父类重名且一模一样的函数, 称之为: 方法重写.
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
​
# 在main函数中测试
if __name__ == '__main__':
    # 4. 创建子类的对象
    p = Prentice()
    # 5. 尝试打印 p对象的 属性 和 行为
    print(f'属性: {p.kongfu}')
    p.make_cake()
    print('-' * 21)
​
    # 6. 演示方法的解析顺序, 即: MRO, 看看方法优先会从哪些类中找.
    print(Prentice.__mro__)     # 输出: Prentice >  School > Master > object, 封装成: 元组
    print(Prentice.mro())       # 输出: Prentice >  School > Master > object, 封装成: 列表

重写后调用父类

父类名.父类方法名(self)

故事4

很多顾客都希望能吃到徒弟做出的有自己独立品牌的煎饼果子,也有学校配方技术的煎饼果子味道。

代码

# 1. 创建1个师傅类, 充当父类.
class Master(object):
    # 1.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'
        self.name = 'Master'
​
    # 1.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
# 2. 创建1个师傅类, 充当父类.
class School(object):
    # 2.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[AI煎饼果子配方]'
​
    # 2.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
# 3. 定义徒弟类, 继承自师傅类.
class Prentice(School, Master):
    # 3.1 定义本类(子类)的 属性.
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'
​
    # 3.2 定义本类(子类)的 行为, 表示: 摊煎饼.
    def make_cake(self):        # 子类出现和父类重名且一模一样的函数, 称之为: 方法重写.
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
    # 3.3 定义函数 make_master_cake(), 表示: 古法摊煎饼果子配方.
    def make_master_cake(self):
        # 前提(细节): 需要重新初始化一下父类的 属性.
        Master.__init__(self)
        # 调用Master#make_cake()
        Master.make_cake(self)
​
    # 3.4 定义函数 make_school_cake(), 表示: AI摊煎饼果子配方.
    def make_school_cake(self):
        # 前提(细节): 需要重新初始化一下父类的 属性.
        School.__init__(self)
        # 调用School#make_cake()
        School.make_cake(self)
​
# 在main函数中测试
if __name__ == '__main__':
    # 4. 创建子类的对象
    p = Prentice()
    # 5. 尝试打印 p对象的 属性 和 行为
    print(f'属性: {p.kongfu}')    # 独创煎饼果子配方
    p.make_cake()                # 独创煎饼果子配方
    print('-' * 21)
​
    # 6. 调用父类 Master类的 古法煎饼果子配方
    p.make_master_cake()         # 古法
    print('-' * 21)
​
    # 7. 调用父类 School类的 古法煎饼果子配方
    p.make_school_cake()         # AI

super().父类方法()

介绍

概述: 它类似于self, 只不过: self代表本类当前对象的引用. super代表本类对象 父类的引用.大白话: self = 自己, super = 父类作用: 初始化父类成员, 实现 在子类中访问父类成员的.细节: 1. super()在多继承关系中, 只能初始化第1个父类的成员, 所以: super()更适用于 单继承环境. 2. 多继承关系中, 如果想实现精准初始化(操作)某个父类的成员, 可以通过 父类名.父类方法名(self) 3. 在单继承关系中, 用 super() 可以简化代码.

案例

# 3. 定义徒弟类, 继承自师傅类.
class Prentice(School, Master):
    # 3.1 定义本类(子类)的 属性.
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'
​
    # 3.2 定义本类(子类)的 行为, 表示: 摊煎饼.
    def make_cake(self):        # 子类出现和父类重名且一模一样的函数, 称之为: 方法重写.
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
    # 3.3 定义函数 make_old_cake(), 表示: 父类的摊煎饼果子配方.
    def make_old_cake(self):
        # 前提(细节): 需要重新初始化一下父类的 属性.
        super().__init__()
​
        # 调用 父类的#make_cake()
        # Master.make_cake(self)    # 格式1: 父类名.父类方法名(self)
        super().make_cake()         # 格式2: super().父类方法名()

多层继承

介绍

概述: 实际开发中, 类与类之间是可以多层继承的,

例如: 类A继承类B, 类B继承类C, 这就是: 多层继承.例如: A => 继承B => 继承C => 继承object

案例

故事5

N年后,小明老了,想要把“有自己的独立品牌,也有配方技术的煎饼果子味道”的所有技术传授给自己的徒弟。

代码

# 1. 创建1个师傅类, 充当父类.
class Master(object):
    # 1.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'
        self.name = 'Master'
​
    # 1.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
​
# 2. 创建1个师傅类, 充当父类.
class School(object):
    # 2.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[AI煎饼果子配方]'
​
    # 2.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
​
# 3. 定义徒弟类, 继承自师傅类.
class Prentice(School, Master):
    # 3.1 定义本类(子类)的 属性.
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'
​
    # 3.2 定义本类(子类)的 行为, 表示: 摊煎饼.
    def make_cake(self):  # 子类出现和父类重名且一模一样的函数, 称之为: 方法重写.
        print(f'使用 {self.kongfu} 制作煎饼果子')
​
    # 3.3 定义函数 make_master_cake(), 表示: 古法摊煎饼果子配方.
    def make_master_cake(self):
        # 前提(细节): 需要重新初始化一下父类的 属性.
        Master.__init__(self)
        # 调用Master#make_cake()
        Master.make_cake(self)
​
    # 3.4 定义函数 make_school_cake(), 表示: AI摊煎饼果子配方.
    def make_school_cake(self):
        # 前提(细节): 需要重新初始化一下父类的 属性.
        School.__init__(self)
        # 调用School#make_cake()
        School.make_cake(self)
​
​
# 4. 定义徒孙类, 继承: 徒弟类.
class TuSun(Prentice):  # 继承关系:  TuSun => Prentice => School, Master => object
    pass
​
​
# 在main函数中测试
if __name__ == '__main__':
    # 4. 创建 徒孙类 的对象
    ts = TuSun()
​
    # 5. 调用父类的成员.
    print(f'属性: {ts.kongfu}')  # 独创煎饼果子配方
    ts.make_cake()  # 独创煎饼果子配方
​
    ts.make_master_cake()  # 古法
    ts.make_school_cake()  # AI

 

 

 

 

二. 封装

封装介绍

概述:

封装指的是 隐藏对象的属性 和 实现细节, 仅对外提供公共的访问方式.

问题

问1: 怎么隐藏 对象的属性 和 实现细节(函数)?答: 通过 私有化解决.

问2: 公共的访问方式是什么?答: get_xxx(), set_xxx()函数.

问3: get_xxx()和set_xxx()函数 必须成对出现吗?答: 不一定, 看需求, 如果只获取值就用 get_xxx(), 如果只设置值就用 set_xxx(). 如果需求不明确, 建议都写.

问4: 封装指的就是 私有, 这句话对吗?答: 不对, 因为我们常用的函数也是封装的一种体现.

好处:

1. 提高代码的安全性. 通过 私有化 实现的. 2. 提高代码的复用性. 通过 函数 实现的.

弊端:

代码量增量了, 封装的代码量会变多. 这里的代码量增加指的是: 私有化以后, 就要提供公共的访问方式, 私有化内容越多, 公共的访问方式就越多, 代码量就越多.

私有化介绍

格式

__属性名__函数名()

特点

只能再本类中直接访问, 外界无法直接调用

私有属性案例

故事6

小明把技术传承给徒弟的同时,不想把自己的私房钱($500000)继承给徒弟,这时就要为钱这个属性设置私有权限。

代码

# 1. 定义徒弟类, 有自己的属性 和 行为.
class Prentice(object):
    # 1.1 属性
    def __init__(self):
        self.kongfu = '[独创的煎饼果子配方]'
        # 私有的属性.
        # self.__money__ = 500000     # 这个不是私有, 就是变量名叫: __money__
        self.__money = 500000         # 这个才是私有化的写法.
​
    # 1.2 对外提供公共的访问方式, 可以实现: 获取私有的变量, 以及给变量设置值.
    # 获取值.
    def get_money(self):
        return self.__money
​
    # 设置值
    def set_money(self, money):
        # 可以在这里对 money属性做判断, 但是没必要. 因为Python属于后端代码, 这里的钱肯定是前端传过来的, 而传过来的数据已经经过了前端的校验.
        # 换言之, 这里如果校验就属于 二次校验了.  实际开发中, 重要字段会做二次校验, 否者可以不做校验.
        # if money > 0:
        #     self.__money = money
        # else:
        #     self.__money = 0
        self.__money = money
​
    # 1.3 行为
    def make_cake(self):
        print(f'采用 {self.kongfu} 制作煎饼果子!')
        # 验证: 私有成员, 在本类中是可以直接访问的.
        print(f'私房钱为: {self.__money}')
​
# 2. 定义徒孙类, 继承自徒弟类.
class TuSun(Prentice):
    pass
​
# 在main函数中测试调用
if __name__ == '__main__':
    # 3. 创建徒孙类对象.
    ts = TuSun()
    # 4. 尝试访问父类的成员.
    # 父类的公共的 属性 和 行为.
    print(f'父类的属性: {ts.kongfu}')
    ts.make_cake()
    print("-" * 21)
    # 父类的 私有的 属性.
    # print(f'父类的私有属性: {ts.money}')   # 报错, AttributeError
    # print(f'父类的私有属性: {ts.__money}')   # 报错, AttributeError
    print(f'父类的私有属性, 通过 公共的方式访问: {ts.get_money()}')
​
    # 通过父类的公共方式, 修改 父类的私有属性.
    ts.set_money(10)
​
    print(f'父类的私有属性, 通过 公共的方式访问: {ts.get_money()}')

私有方法案例

父类的私有化方法, 也需要提供1个公共的访问方式, 让子类来访问.

故事7

小明把煎饼果子技术传承给徒弟的同时,不想把自己的独创配方制作过程继承给徒弟,这时就要为制作独创配方这个方法设置私有权限。

代码

# 1. 定义徒弟类, 有自己的属性 和 行为.
class Prentice(object):
    # 1.1 属性
    def __init__(self):
        self.kongfu = '[独创的煎饼果子配方]'
        # 私有的属性.
        # self.__money__ = 500000     # 这个不是私有, 就是变量名叫: __money__
        self.__money = 500000         # 这个才是私有化的写法.
​
    # 1.2 对外提供公共的访问方式, 可以实现: 获取私有的变量, 以及给变量设置值.
    # 获取值.
    def get_money(self):
        return self.__money
​
    # 设置值
    def set_money(self, money):
        self.__money = money
​
    # 1.3 行为
    def __make_cake(self):
        print(f'采用 {self.kongfu} 制作煎饼果子!')
        # 验证: 私有成员, 在本类中是可以直接访问的.
        print(f'私房钱为: {self.__money}')
​
    # 针对于父类的私有方法, 提供公共的访问方式(在其内部调用 私有化的方法即可)
    def my_make(self):
        # 调用私有化方法 __make_cake()
        self.__make_cake()
​
# 2. 定义徒孙类, 继承自徒弟类.
class TuSun(Prentice):
    # 演示用, 在子类中 恶意的修改 父类的函数内容. 通过 方法重写 实现.
    # def make_cake(self):
    #     print('加入调料: 砒霜')
    #     print('加入调料: 鹤顶红')
    #     print('加入调料: 含笑半步癫')
    #     print('加入调料: 一日断肠散')
    #     # 调用父类的方法.
    #     super().make_cake()
​
    pass
​
# 在main函数中测试调用
if __name__ == '__main__':
    # 3. 创建徒孙类对象.
    ts = TuSun()
​
    # 4. 尝试访问父类的成员.
    # 4.1 父类的 私有的 属性.
    print(f'父类的私有属性, 通过 公共的方式访问: {ts.get_money()}')
    # 通过父类的公共方式, 修改 父类的私有属性.
    ts.set_money(10)
    print(f'父类的私有属性, 通过 公共的方式访问: {ts.get_money()}')
    print('-' * 21)
​
    # 4.2 父类的 私有的 方法(行为).
    # ts.__make_cake()        # AttributeError, 父类私有成员(方法), 子类无法直接访问.
    # ts.make_cake()
    ts.my_make()

 

 

三. 多态

多态指的是同一个事物在不同时刻, 不同场景下表现出来的不同形态, 状态.

介绍

前提条件

  1. 要有继承关系.

    扩展: 没有继承关系也行, 因为Python是弱类型的, 对数据的类型限定不严格, 可以称之为 => 伪多态.

  2. 要有方法重写, 否则无意义.

  3. 要有父类引用指向子类对象.

好处

提高代码的可维护性.

即: 同样的一个函数, 未来需求变化了, 我们传入不同的参数即可, 无需修改源码, 既有不同的结果.

扩展: 开发原则, 对修改关闭, 对扩展开放.

大白话: 需求变化了, 不能该源码, 尽量加代码.

弊端

不知道传入的是哪一个具体的子类, 所以无法直接访问子类的特有成员.

应用场景

父类型作为方法形参的数据类型, 这样可以接受其任意的子类对象, 实现传入什么子类对象, 就调用其对应的功能.

案例1:动物

# 1. 定义父类, 动物类, 有个speak()函数.
class Animal(object):
    def speak(self):
        pass
​
# 2. 定义子类, 狗类, 继承自动物类, 重写Animal#speak()函数.
class Dog(Animal):
    # 重写父类的speak()函数
    def speak(self):
        print('汪汪汪!')
​
# 3. 定义子类, 猫类, 继承自动物类, 重写Animal#speak()函数.
class Cat(Animal):
    def speak(self):
        print('喵喵喵!')
​
    def catch_mouse(self):
        print('猫会抓老鼠!')
​
# 4.假设需求变化, 增加了 猴子类.
class Monkey(Animal):
    def speak(self):
        print('桀桀桀!')
​
# 验证Python是伪多态, 即: print_animal()函数, 不传入Animal的子类的对象, 也行.
class Phone:
    def speak(self):
        print('手机叫一次, 你要唱一首歌!')
​
# 5. 定义函数, 接收Animal类型, 调用speak()函数.
# def print_animal(an):   # an:Animal = Dog(),   an:Animal = Cat(), 父类引用指向子类对象.
def print_animal(an: Animal):   # an:Animal = Dog(),   an:Animal = Cat(), 父类引用指向子类对象.
    an.speak()
    # an.catch_mouse() 不能访问子类的 特有成员.
​
​
# 6. 在main函数中测试
if __name__ == '__main__':
    # 6.1 创建猫对象, 狗对象.
    cat = Cat()
    dog = Dog()
    mon = Monkey()
​
    # 6.2 调用print_animal()函数.
    # 发现: 同一个函数, 接受不同的对象, 实现效果不一样 => 多态.
    print_animal(cat)
    print('-' * 21)
    print_animal(dog)
    print('-' * 21)
    print_animal(mon)
    print('-' * 21)
​
    # 7. 调用print_animal()函数, 传入 非Animal类的子类.
    phone = Phone()
    print_animal(phone)

案例2:飞机

需求

构建对象对战平台object_play,

  1. 英雄一代战机(战斗力60)与敌军战机(战斗力70)对抗。英雄1代战机失败!

  2. 卧薪尝胆,英雄二代战机(战斗力80)出场!,战胜敌军战机!

  3. 对象对战平台object_play, 代码不发生变化的情况下, 完成多次战斗

代码

# 1. 构建 1代 英雄机.
class HeroFighter(object):
    def power(self):
        return 60   # 战斗力: 60
​
# 2. 构建 2代 英雄机.
class AdvHeroFighter(HeroFighter):
    def power(self):
        return 80   # 战斗力: 80
​
# 3. 构建 敌机.
class EnemyFighter(object):
    def power(self):
        return 70   # 战斗力: 70
​
# 4. 搭建对战平台, 即: 通用的函数, 接收不同的参数, 效果不同, 但是函数还是那个函数.
def object_play(hf:HeroFighter, ef:EnemyFighter):
    # 具体的战斗过程
    if hf.power() > ef.power():
        print('英雄机获得胜利!')
    elif hf.power() < ef.power():
        print('敌机惨胜!')
    else:
        print('平局!')
​
​
# 5. 在main函数中测试.
if __name__ == '__main__':
    # 5.1 创建 各种战机.
    hf1 = HeroFighter()     # 1代英雄机
    hf2 = AdvHeroFighter()  # 2代英雄机
    ef = EnemyFighter()     # 敌机
​
    # 5.2 具体的对战过程.
    # Pythong中的多态: 同一个函数 接受不同的参数 实现不同的效果 => 多态
    object_play(hf1, ef)    # 1代英雄机 和 敌机
    print('-' * 21)
    object_play(hf2, ef)    # 2代英雄机 和 敌机

抽象类

介绍

概述: 有抽象方法的类就叫 抽象类, 也可以称之为: 接口.抽象方法: 没有方法体的方法, 叫: 抽象方法, 即: 方法体是用 pass 来编写的.作用/目的: 抽象类: 一般充当父类, 用于制定: 标准. 子类: 普通类 继承抽象类, 重写抽象方法, 提供具体的实现即可.

案例:空调

需求

创建AC类(空调类), 表示空调的标准, 热风, 冷风, 左右摆风...不同的子类来实现这些功能. 例如: 格力, 美的...

代码

# 1. 定义AC类(空调类, 抽象类), 表示: 空调的标准.
class AC(object):
    # 1.1 制冷, 抽象方法(没有方法体的方法)
    def cool_wind(self):
        pass
​
    # 1.2 热风
    def hot_wind(self):
        pass
​
    # 1.3 左右摆风
    def swing_l_r(self):
        pass
​
# 2. 定义Gree类(格力空调类), 继承: AC类.
class Gree(AC):
    # 2.1 重写 AC#cool_wind 方法
    def cool_wind(self):
        print('格力空调 核心制冷技术 制作冷风')
​
    # 2.2 重写 AC#hot_wind 方法
    def hot_wind(self):
        print('格力空调 核心制热技术 制作热风')
​
    # 2.3 重写 AC#swing_l_r 方法
    def swing_l_r(self):
        print('格力空调 左右摆风!')
​
# 3. 定义Media类(美的空调类), 继承: AC类.
class Media(AC):
    # 3.1 重写 AC#cool_wind 方法
    def cool_wind(self):
        print('美的空调 核心制冷技术 制作冷风')
​
    # 3.2 重写 AC#hot_wind 方法
    def hot_wind(self):
        print('美的空调 核心制热技术 制作热风')
​
    # 3.3 重写 AC#swing_l_r 方法
    def swing_l_r(self):
        print('美的空调 左右摆风!')
​
# 定义函数, 测试空调的性能.
def my_ac(ac: AC):
    ac.cool_wind()
    ac.hot_wind()
    ac.swing_l_r()
​
# 4. 在main函数中测试.
if __name__ == '__main__':
    # 非多态方式
    # 4.1 测试 格力空调.
    g = Gree()
    g.cool_wind()
    g.hot_wind()
    g.swing_l_r()
    print('-' * 21)
​
    # 4.2 测试 美的空调.
    m = Media()
    m.cool_wind()
    m.hot_wind()
    m.swing_l_r()
    print('-' * 21)
​
    # 5. 多态方式.
    my_ac(g)
    print('-' * 21)
    my_ac(m)

 

 

四. 面向对象其他特性

类属性和对象属性

名词解释

对象属性

概述: 属于 对象的属性, 即: 每个对象都有, 且A对象的属性值修改了 不会影响 B对象的属性值. 类似于: 你个人的钱包.

定义格式: 类外: 对象名.属性名 = 属性值 类内: 写到 init魔法方法中, self.属性名 = 属性值

调用格式: 类外: 对象名.属性名 类内: self.属性名

类属性

概述: 属于 类的属性, 即: 可以被 该类下所有的对象所共享. 即: 无论是谁修改了这个变量的值, 之后大家用的都是修改后的.

定义格式: 定义在类中, 方法外的位置, 写法和以前我们写变量的格式 一样.

调用格式: 方式1: 类名.属性名 方式2: 对象名.属性名 可以这样写, 但是不推荐.

细节: 修改类属性必须通过 类名.属性名 = 属性值 的方式来修改, 不能通过 对象名.属性名 = 属性值的方式来修改. 因为: 前者是在修改 类属性的值, 后者是在 给对象新增1个属性.

技巧

简单记忆, 类变量的获取 和 修改都通过 类名. 的方式来操作, 肯定不会报错.

演示

# 1. 定义学生类.
class Student:
    # 1.1 定义 类属性(类变量).
    teacher_name = '哥'
​
    # 1.2 对象属性, 类内 设置.
    def __init__(self):
        self.name = '张三'    # 对象属性, 该类的每个对象都有.
​
# 在main函数中测试.
if __name__ == '__main__':
    # 2. 创建学生类对象.
    s1 = Student()
    s2 = Student()
​
    # 3. 对象属性, 在类外 设置 对象属性.
    s1.name = '李四'
    s1.age = 21     # 只有s1对象有.
​
    # 4. 对象属性, 在类外 获取 对象属性.
    print(f'类外获取对象属性值: {s1.age}')       # 21
    print(f'类外获取对象属性值: {s1.name}')      # 李四
    print(f'类外获取对象属性值: {s2.name}')      # 张三
    print("-" * 21)
​
    # 5. 在类外, 访问类属性
    # 方式1: 类名. 的方式
    print(Student.teacher_name)     # 哥
    # 方式2: 对象名. 的方式, 可以, 但是不推荐.
    print(s1.teacher_name)          
    print(s2.teacher_name)          
    print("-" * 21)
​
    # 6. 修改类属性的值.
    Student.teacher_name = '老师'     # 可以修改 类属性值
    s1.teacher_name = '老师'          # 不是在修改类变量的值, 而是在给s1对象新增1个属性值.
​
    # 7. 重新打印 类属性的值.
    # 方式1: 类名. 的方式
    print(Student.teacher_name)  # 老师
    # 方式2: 对象名. 的方式, 可以, 但是不推荐.
    print(s1.teacher_name)  # 老师
    print(s2.teacher_name)  # 老师

 

类方法和静态方法

名词解释

类方法

概述: 它表示属于类的方法, 可以被所有的对象共享.细节: 1. 必须用装饰器 @classmethod 来修饰. 2. 第一个参数必须是 cls, 表示: 当前类的 引用, 即: 等价于 类名. 的形式 3. 类方法可以被 对象名. 或者 类名. 的方式来调用, 推荐使用 后者.

静态方法

概述: 它表示属于 所有对象所共享 的方法, 可以被所有的对象共享.细节: 1. 必须用装饰器 @staticmethod 来修饰. 2. 无参数要求, 根据需求来即可, 可传可不传. 3. 静态方法可以被 对象名. 或者 类名. 的方式来调用, 推荐使用 后者.

区别

  1. 用的装饰器不同.类方法: @classmethod静态方法: @staticmethod

  2. 是否必须要传 第1个参数.类方法: 必须传cls参数, 表示 当前类的引用.静态方法: 根据需求来即可, 可传可不传.

 

演示

# 1. 定义学生类.
class Student:
    name = 'AI'   # 类属性
​
    def __init__(self):
        self.age = 18     # 对象属性
​
    def method(self):
        print('我是method函数, 普通方法')
​
    @staticmethod
    def method2():
        print('我是method2方法, 我是静态方法')
        print(f'调用类属性: {Student.name}')
​
    @classmethod
    def method3(cls):   # cls来源于 class单词
        # self = 本类对象的引用, 类似于 对象名.
        # cls = 本类的引用, 类似于: 类名.
        print('我是method3方法, 我是类方法')
        print(f'cls表示类属性, 内容为: {cls}')  # <class '__main__.Student'>
        print(f'调用类属性: {cls.name}')
​
# 在main函数中测试.
if __name__ == '__main__':
    # 2. 创建对象.
    s1 = Student()
​
    # 3. 访问 静态方法
    Student.method2()       # 方式1: 类名.
    s1.method2()            # 方式2: 对象名.
    print('-' * 21)
​
    # 4. 访问 类方法
    Student.method3()      # 方式1: 类名.
    s1.method3()           # 方式2: 对象名.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Ubuntu下全面解析硬盘健康:从基础检测到性能优化 本文详细介绍了在Ubuntu系统中如何全面监测硬盘健康状态。从安装smartmontools工具、解读SMART关键属性(如重新分配扇区计数、通电时间),到进行性能基准测试(使用dd和fio),最后根据检测结果提供针对性的优化与预警方案,帮助用户有效预防数据丢失并提升硬盘可靠性。 阅读详情

相关推荐

【深度剖析】三一重工的数字化转型(中篇)

三一重工在数字化转型方面取得了提高效率、降低成本、加强研发创新和改善内控管理等多方面的成效。本研究旨在通过对三一重工数字化转型的深入分析,引导企业思考在第四次工业革命与第三次能源革命交汇的超级技术窗口期,如何进一步把握发展机遇,并为同行业其他企业提供探索性的建议。作为装备制造行业的佼佼者,三一重工的数字化转型受到了业界的广泛关注。作为行业内首批接触并实践数字化转型的企业之一,三一重工的转型经验不仅成功,而且积累了丰富的理论与实践,为其他制造业企业的数字化转型提供了可借鉴的范例。

领信卓越的博客 2295

day19 面向对象高级和应用

day19 面向对象高级和应用 版权声明:本博客转载自路飞学城Python全栈开发培训课件,仅用于学习之用,严禁用于商业用途。 欢迎访问路飞学城官网:https://www.luffycity.com/ 课程目标:掌握面向对象高级知识和相关应用。 今日概要 继承【补充】 内置函数【补充】 异常处理 反射 1. 继承【补充】 对于Python面向对象中的继承,我们已学过: 继承存在意义:将公共的方法提取到父类中,有利于增加代码重用性。 继承的编写方式: # 继承 class Base(objec

mannixiang的博客 214

十一、机器学习进阶知识:径向基神经网络(RBFNN)的实现(Python,附源码及数据集)

本文对径向基神经网络(RBFNN)的理论基础及建模步骤进行介绍,之后使用Python实现基于RBFNN的数据预测,通俗易懂,适合新手学习,附源码及实验数据集。

weixin_42051846的博客 1万+

Day02_面向对象高级

封装:就是将属性和行为书写到类,隐藏属性和实现细节,仅对外提供公共的访问方式。封装会隐藏对象的属性和行为,仅对外提供访问权限优势:能够提高代码的安全性、复写性弊端:代码量增加(用继承可以缓解这个问题)继承:多个类中的内容重复性较高时,将重复的内容提炼到一个类中,其他类继承这个类优势:提高复写性、可维护性弊端:耦合增强(类与类之前关联过高,父类增加一个成员子类也会增加,但可以使用私有成员缓解这个问题)多态:同一事物的不同状态(伪多态,java是真多态)

l12345sy的博客 444

DaVinci Developer中枚举类型变量的创建与实战应用

本文详细介绍了在DaVinci Developer中创建和使用枚举类型变量的方法与实战应用。通过智能温控系统的案例,阐述了枚举类型在嵌入式开发中的核心价值,包括提升代码可读性、类型安全性和维护便捷性。文章还提供了枚举类型在状态机实现和多模块协同中的高级应用技巧,以及调试与优化的实用建议。

ik678901234的博客 506

Kimi K3大模型API实战:从调用到本地知识库问答系统构建

大语言模型(LLM)作为人工智能的核心技术,通过海量数据训练获得理解和生成自然语言的能力。其工作原理基于Transformer架构,通过自注意力机制捕捉长距离依赖关系。这项技术的核心价值在于能够将非结构化文本转化为可计算、可交互的智能体,极大地提升了信息处理和自动化任务的效率。在应用场景上,大模型广泛应用于智能对话、代码生成、文档总结与问答等领域。其中,国产大模型如月之暗面推出的Kimi K3,凭借其在**长文本处理**和**中文场景优化**方面的优势,为开发者提供了新的技术选项。本文将以Kimi K3为例

weixin_30694389的博客 282

21 天 Python 计划:面向对象高级

Python是一种强大且易于学习的编程语言。通过这个21天的计划,我们将逐步深入面向对象高级。无论你是初学者还是有一定基础的开发者,这个计划都将帮助你巩固和扩展你的Python知识。day1:Python下载和开发工具介绍day2:数据类型、字符编码、文件处理day3:基础语法与课外练习day4:函数简单介绍day5:模块与包day6:常用模块介绍day7:面向对象isinstance(obj, cls):用于检查对象 obj是否是类 cls或其派生类的实例。

懂搬砖 1776

Origin科研绘图——桑基图

是一种用于展示“流动”(flow)关系的可视化图表,常用于呈现能量流、物质流、资金流、信息流等在不同节点之间的传递和分配情况。它最大的特点是用“宽度可变的流线”来直观表示数量大小——流线越宽,代表流量越大,因此特别适合理解复杂系统中资源从哪里来、到哪里去、以及不同路径所占比例。为该流程对应的数量。只需将各个流程逐项填写在 A、B、C 三列即可,流程的排列顺序并非关键,确保起点、终点及对应数值准确才是最重要的。与柱状图、饼图不同,桑基图不仅展示“多少”,还展示“从哪到哪”。至此,本期教程就结束啦。

weixin_41301530的博客 1387

Python高级编程 day13 面向对象(一)

本文主要讲解了对面向对象的初步认识,通过本文,你将对面向对象具有一定的理解并可以简单编写。

2401_88454635的博客 1381

数据科学常见模型总结(二)-倾向性得分匹配模型

PSM的核心思想是从未受干预的用户群体中,找到和干预对象一模一样的用户,这样就可以把因果效应归因到干预上。

wudelong0112的专栏 4870

TOGAF9.2/10 认证基础知识点概览表

(考点解析:业务场景是一种重要的技术,可以在企业架构的各个阶段使用,主要是架构愿景和业务架构,但如果需要,也可以在其他架构域中使用,以直接从业务的高级需求中派生架构的特征。“哪里”可以看作是对相关企业的界定、“为什么”可以被视为组织环境中的关键驱动因素和要素、“谁”是指确定发起人利益相关者和受业务指令影响的其他主要利益相关者,以创建企业架构,并确定他们来自企业的需求和优先级、他们与企业的关系以及彼此之间所需的工作行为。它是业务驱动和业务主导的,它结 合了所有业务线的必要努力,以实现所需的能力。

2302_81497763的博客 2066

面向对象—02面向对象高级特性

一、类属性与实例属性 类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在 一个副本。 在前面的例子中我们接触到的就是实例属性(对象属性),它不被所有类对象的实 例对象所共有,在内存中的副本个数取决于对象个数。 二、类方法与静态方法 ...

小黑的博客 489

YOLO26涨点改进 |独家创新,小目标涨点改进篇 | Arxiv 2025 | MHAF‑YOLO,引入RepHMS高效特征提取模块,适合轻量级目标检测、小目标检测、图像分类、旋转目标检测、实例分割

本文提出了一种改进的YOLO26目标检测模型,通过引入RepHMS模块和多分支辅助特征金字塔结构(MAFPN),显著提升了模型性能。RepHMS模块采用多分支异构卷积和重参数化策略,在不增加推理开销的情况下增强多尺度特征提取能力,尤其提升了小目标检测效果。实验表明,改进后的MHAF-YOLO模型在COCO数据集上仅用7.1M参数就达到48.9% AP,相比YOLO11-s参数量减少24.4%而性能提升1.9%。文章详细介绍了RepHMS模块的原理、实现代码及在YOLO26中的集成方法,并提供了两种改进配置。

Ai缝合怪、助力小伙伴高效发论文 194

Day6—面向对象高级

本节内容: 面向对象高级语法部分      经典类vs新式类       静态方法、类方法、属性方法     类的特殊方法     反射 异常处理 Socket开发基础 面向对象高级语法部分 经典类vs新式类 把下面代码用python2 和python3都执行一下 class A: def __init__(self):...

a13126535203的博客 131

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Python之面向对象高级特性

面向对象高级特性类属性与实例属性类方法与静态方法property类属性 类属性与实例属性 类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本。 在前面的例子中我们接触到的就是实例属性(对象属性),它不被所有类对象的实例对象所共有,在内存中的副本个数取决于对象个数。 class People(object): #属性名和对象没有绑定在一起,为类属性: ...

weixin_44026431的博客 216

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Day19 面向对象高级和应用

day19 面向对象高级和应用 课程目标:掌握面向对象高级知识和相关应用。 今日概要 继承【补充】 内置函数【补充】 异常处理 反射 1. 继承【补充】 对于Python面向对象中的继承,我们已学过: 继承存在意义:将公共的方法提取到父类中,有利于增加代码重用性。 继承的编写方式: # 继承 class Base(object): pass class Foo(Base): pass # 多继承 class Base(object): pass class Bar

从不喝奶茶的博客 164

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Python高级编程 day14 面向对象--封装

本文主要讲述了面向对象三大特征之一的封装以及面向对象的绑定,非绑定方法。学习之后可以将对象简单进行属性隐藏与手动绑定。

2401_88454635的博客 1500

AI大模型开发第二阶段Day02python面向对象高级

本文总结了Python面向对象编程中类的定义语法和继承机制。主要内容包括: 定义类的三种语法形式,推荐使用class 类名(object)的新式类定义方式。 继承的概念和作用:提高代码复用率,减少重复代码。 单继承和多继承的实现方法,子类默认继承父类属性和方法。 子类重写父类同名属性和方法的方式,以及使用类名.__mro__查看方法调用顺序。 在子类中调用父类方法的方式,包括使用父类名直接调用。 文章通过摊煎饼师傅与徒弟的案例,生动演示了继承、方法重写和父类方法调用的具体应用场景。

weixin_46411355的博客 434

Python高级编程day1.初识面向对象

Python高级面向对象

m0_73467845的博客 943

Day07-1【面向对象高级编程】概述

在 Python 的面向对象编程(OOP)中,数据封装、继承和多态这三大基础概念是每个开发者都必须掌握的基本功。但是,掌握了这些之后,我们就进入了 Python 面向对象的“进阶关卡”。在这里,我们会遇到更加酷炫和强大的特性,比如多重继承、定制类和元类——这些概念让我们可以用更灵活、更强大的方式,写出令人惊叹的代码。

max202011161630的博客 890

python面向对象进阶_day009

python面向对象进阶,有趣的示例

slb190623的博客 2640

python高级day3

练习

ljd210323124的博客 1340

Day10-python面向对象编程

面向对象编程(OOP)是一种以对象为核心的编程范式,通过类封装数据与行为,实现代码复用和模块化。编程方式经历了从机器语言到高级语言的演进,OOP因能解决复杂系统问题而成为主流。类作为对象的模板,包含属性和方法,具有封装、继承和多态三大特性;对象则是类的实例,具有独立性和动态性。Python中"万物皆对象",包括基础数据类型、函数等。OOP提高了代码可维护性和扩展性,适应现代软件开发需求。

qq_33388535的博客 2124

Python高级编程 day15 面向对象--继承,多态

本文主要讲述了面向对象的继承和多态这两大特征,简要介绍了三个内置方法。

2401_88454635的博客 1055

day09-测试编程之python的面向对象

1).语法格式2).说明:类名必须符合大驼峰命名法3).方法和函数的区别3.1).相同点:都是封装代码的整体,都是实现某个功能的小工具3.2).不同点(1).定义的位置不同1.函数定义在类的外部2.方法定义在类的内部(2).参数不同1.函数没有self参数2.方法有self参数(3).调用的方式不同1.函数名(参数)2.对象名.方法名(参数)

Jay1900-陈的博客 1315

轩小陌的Python笔记-day19 面向对象高级和应用

day19 面向对象高级和应用 课程目标:掌握面向对象高级知识和相关应用。 今日概要 继承【补充】 内置函数【补充】 异常处理 反射 1. 继承【补充】 对于 Python 面向对象中的继承,之前已讲解过: 继承存在意义:将公共的方法提取到父类中,有利于增加代码重用性。 继承的编写方式: # 继承 class Base(object): pass class Foo(Base): pass # 多继承 class Base(object): pass class

hjjqazwsx的博客 628
上一篇: python进阶篇-day01-面向对象基础
下一篇: python进阶篇-day03-学生管理系统与深浅拷贝
开出南方的花
博客等级 码龄5年 1431粉丝 62原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值