python 面向对象语法进阶

1.定义类的格式

  • 格式如下:
格式1:
    class 类名:
        pass

格式2:
    class 类名():
        pass

格式3:
    class 类名(object):
        pass
  • 注意:

    • object 是所有类的父类,所有类直接或间接继承自object.
  • 代码如下:

# 需求: 定义老师类.

# 格式1
# class Teacher:
#     pass

# 格式2
# class Teacher():
#     pass

# 格式3
class Teacher(object):
    pass

# 在main中测试
if __name__ == '__main__':
    # 创建老师类对象
    t1 = Teacher()
    print(t1)   #打印结果为地址值

2.继承

  • 概述
    ​ 实际开发中,很多类中的部分都是相似的,针对这种情况把相似的部分抽取出来放到1个类中(父类),然后让多个子类和这个类产生关系这就叫继承.

  • 格式

    • class 子类名(父类名):
      ​ pass
  • 好处:

    • 1.提高代码复用性
    • 2.提高代码可维护性
  • 弊端

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

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

案例: 父类有默认性别男, 爱好散步行走, 定义子类继承父类, 看是否可以访问这些属性 和 行为.

# 1. 定义父类.
class Father:
    # 1.1 定义父类的属性.
    def __init__(self):
        self.gender = '男'

    # 1.2 定义父类的行为
    def walk(self):
        print('饭后走一走, 能活九十九!')
        print('饭后一支烟, 赛过活神仙!')
       

# 2. 定义子类, 继承自父类.
class Son(Father):
    pass

# 在main中测试
if __name__ == '__main__':
    # 3. 创建子类的对象.
    s = Son()
    # 4. 尝试打印 s对象的 属性 和 行为
    print(f'性别: {s.gender}')
    s.walk()

2.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()  # 从父类继承来的行为.

2.2 多继承

  • 注意
      1. Python中支持多继承写法, 即: 1个类可以有多个父类, 写法为: class 子类名(父类名1, 父类名2…)
      1. 多继承关系中, 子类可以继承所有父类的属性和行为. 前提: 父类的私有成员除外.
      1. 多继承关系中, 多个父类如果有重名属性或者方法时, 子类会优先使用第1个父类(即: 最前边的父类)的该成员.
      1. 上述的继承关系, 我们可以通过 Python内置的 mro属性 或者 mro()方法来查看.
        mro: Method Resolution Order, 即: 方法的解析顺序(调用顺序)

案例:小明是个爱学习的好孩子,想学习更多的摊煎饼果子技术,于是,在百度搜索学习摊煎饼果子技术。

# 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 = '[百度学习煎饼秘籍]'

    # 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, 封装成: 列表

2.3方法重写

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

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

# 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 = '[百度学习煎饼秘籍]'

    # 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, 封装成: 列表

2.3.1重写后-子类访问父类的成员-写法1
  • 格式:
    格式1:父类名.父类方法名(self)
    ​ 格式2: super().父类方法名()

  • 案例:
    格式1写法

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

# 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 = '[百度学习煎饼秘籍]'

    # 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(), 表示: 百度秘籍摊煎饼果子配方.
    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()         # 百度学习
2.3.2重写后-子类访问父类的成员-写法2 super
  • super关键字介绍:

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

  • 案例:
    格式2写法:super

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

# 1. 创建1个师傅类, 充当父类.
class Master(object):
    # 1.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[煎饼果子秘籍]'

    # 1.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')

# 2. 创建1个师傅类, 充当父类.
class School(object):
    # 2.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[百度学习煎饼秘籍]'

    # 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_old_cake(), 表示: 父类的摊煎饼果子配方.
    def make_old_cake(self):
        # 前提(细节): 需要重新初始化一下父类的 属性.
        super().__init__()       #默认是左边为第一个 推荐单继承使用

        # 调用 父类的#make_cake()
        # Master.make_cake(self)    # 格式1: 父类名.父类方法名(self)
        super().make_cake()         # 格式2: super().父类方法名()


# 在main函数中测试
if __name__ == '__main__':
    # 4. 创建子类的对象
    p = Prentice()
    # 5. 尝试打印 p对象的 属性 和 行为
    print(f'属性: {p.kongfu}')    # 独创煎饼果子配方
    p.make_cake()                # 独创煎饼果子配方
    print('-' * 21)

    # 6. 调用父类的 煎饼果子配方
    p.make_old_cake()            # 百度学习煎饼秘籍

3.多层继承

  • 概述:
    ​ 类与类之间是可以多层继承的 如:类A继承类B,类B继承类c等.

  • 例如:
    ​ A = > 继承B => 继承C => 继承object

案例: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 = '[百度学习煎饼秘籍]'

    # 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(), 表示: 百度学习煎饼秘籍.
    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()        # 百度学习煎饼秘籍

4.封装

4.1 封装-私有化属性

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

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

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

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

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

  • 好处:

    1. 提高代码的安全性. 通过 私有化 实现的.
    2. 提高代码的复用性. 通过 函数 实现的.
  • 弊端:
    代码量增量了, 封装的代码量会变多.
    这里的代码量增加指的是: 私有化以后, 就要提供公共的访问方式, 私有化内容越多, 公共的访问方式就越多, 代码量就越多.

  • 私有化介绍

格式:
    __属性名       # 注意: 这里是 两个_
    __函数名()
特点:
    只能在本类中直接访问, 外界无法直接调用.

案例 小明把技术传承给徒弟的同时,不想把自己的私房钱($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):
        # 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()}')

4.2封装-私有化方法

  • 该案例的目的:
    演示 私有化方法. 即: 父类的私有化方法, 也需要提供1个公共的访问方式, 让子类来访问.

  • 问: 什么时候使用私有化呢?
    答: 父类的成员不想被子类直接继承(或者重写, 修改等), 但是还想给子类用, 就可以考虑用私有化.

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


# 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()

5.多态

  • 概述:
    多态指的是同一个事物在不同时刻, 不同场景下表现出来的不同形态, 状态.
  • 大白话解释:
    Python中的多态: 同一个函数 接收不同的参数 会有不同的结果.
    现实生活中的多态: 一杯水, 高温 => 气体, 常温 => 液体, 低温 => 固体.
  • 前提条件:
      1. 要有继承关系. # 扩展: 没有继承关系也行, 因为Python是弱类型的, 对数据的类型限定不严格, 可以称之为 => 伪多态.
      1. 要有方法重写, 否则无意义.
      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)

5.1多态案例

  • 需求:

    • 构建对象对战平台object_play,
      1. 英雄一代战机(战斗力60)与敌军战机(战斗力70)对抗。英雄1代战机失败!
      2. 卧薪尝胆,英雄二代战机(战斗力80)出场!,战胜敌军战机!
      3. 对象对战平台object_play, 代码不发生变化的情况下, 完成多次战斗
  • 分析流程:
    抽象战机类 HeroFighter AdvHeroFighter;敌机EnemyFighter;
    构建对象战斗平台, 使用多态实现

# 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代英雄机 和 敌机

6.抽象类入门

  • 抽象类简介:
    • 概述:
      有抽象方法的类就叫 抽象类, 也可以称之为: 接口.
    • 抽象方法:
      没有方法体的方法, 叫: 抽象方法, 即: 方法体是用 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)

7.类属性与对象属性解释

  • 对象属性解释:

    • 概述:
      属于 对象的属性, 即: 每个对象都有, 且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}')      # 张三

8.类方法与静态方法

  • 类方法解释:

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

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

      1. 用的装饰器不同.
        类方法: @classmethod
        静态方法: @staticmethod
      1. 是否必须要传 第1个参数.
        类方法: 必须传cls参数, 表示 当前类的引用.
        静态方法: 根据需求来即可, 可传可不传.
# 1. 定义学生类.
class Student:
    name = '不想上班'   # 类属性

    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: 对象名.

总结

持续更新中~~~

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值