Pycharm(十六)面向对象进阶

发布于:2025-05-01 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、面向对象三大特性---继承

1.1 继承

概述:

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

通俗解释:

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

格式:

         class 子类名(父类名):

                 pass

优点:

         1.提高代码的复用性; 2.提高代码的可维护性

缺点:

         耦合性增强了,好坏都继承了过来。

         耦合:指的是类与类之间的关系

        细节:

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

示例1.
'''
继承相关概述:
    概述:
        实际开发中,我们发现很多类中的步分内容是相似的,或者相同的,每次写很麻烦,针对这种情况,
        我们可以把这些相似(相同的)部分抽取出来,单独地放到1个类中(父类),
        然后让多个类(子类)和这个类产生关系,这个关系就叫:继承
    通俗解释:
        子承父业,Python中的继承,子类=>继承父类的 属性,行为
    格式:
        class 子类名(父类名):
            pass
    优点:
        1.提高代码的复用性;
        2.提高代码的可维护性。
    缺点:
        耦合性增强了,好坏都继承了过来
        耦合:指的是类与类之间的关系
    细节:
        1.所有的类都直接或间接继承自object,它是所有类的父类,也叫:顶级类
'''
class Father:
    def __init__(self):
        self.gender='男'
    def walk(self):
        print('饭后走一走,能活九十九!')
class Son(Father):
    pass
if __name__ == '__main__':
    s=Son()
    print(f'gender:{s.gender}')
    s.walk()
    print(type(s.walk))

运行结果:

上面代码中的Son类继承了Father类,将Father类中的walk方法和属性都继承了过来。 

1.2 多继承

1. Python中支持多继承写法, 即: 1个类可以有多个父类。

        写法为:   class 子类名(父类名1, 父类名2...)

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

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

4. 上述的继承关系, 我们可以通过 Python内置的 mro属性 或者 mro()方法来查看.  

  mro: Method Resolution Order, 即: 方法的解析顺序(调用顺序)

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

示例2.
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, 封装成: 列表

运行结果:

上述代码中的Prentice类继承了School类和Master类,因为Father类在前,所以和Master有重名类属性和方法时,就会优先继承前边的Father类的属性和方法。

1.3 重写

概述:

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

注意: 重写一般特指: 方法重写.     

细节:

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

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

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

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

        3.细节:
                需要重新初始化一下父类的 属性.

示例3.
"""
案例:
    故事4: 很多顾客都希望能吃到徒弟做出的有自己独立品牌的煎饼果子,也有黑马配方技术的煎饼果子味道。

问: 重写后, 子类如何访问父类的成员呢?
答案:
    格式1: 父类名.父类方法名(self)
    格式2: super().父类方法()
"""

# 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() 可以简化代码.

示例4.
"""
案例:
    故事4: 很多顾客都希望能吃到徒弟做出的有自己独立品牌的煎饼果子,也有黑马配方技术的煎饼果子味道。

问: 重写后, 子类如何访问父类的成员呢?
答案:
    格式1: 父类名.父类方法名(self)
    格式2: super().父类方法()

super关键字介绍:
    概述:
        它类似于self, 只不过: self代表本类当前对象的引用.   super代表本类对象 父类的引用.
    大白话:
        self = 自己, super = 父类
    作用:
        初始化父类成员, 实现 在子类中访问父类成员的.
    细节:
        1. super()在多继承关系中, 只能初始化第1个父类的成员, 所以: super()更适用于 单继承环境.
        2. 多继承关系中, 如果想实现精准初始化(操作)某个父类的成员, 可以通过 父类名.父类方法名(self)
        3. 在单继承关系中, 用 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 = '[黑马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_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()            # 黑马AI

运行结果:

 

二、面向对象三大特性---封装

2.1 封装

概述:

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

问1:怎么隐藏 对象的属性 和 实现细节(函数)?

答:通过 私有化解决

问2:公共的访问方式是什么?

答:get_xxx(),set_xxx()函数.

问3:get_xxx()和set_xxx() 函数 必须成对出现吗?

答:不一定,看需求,如果只获取值就用get_xxx(),如果只设置值就用set_xxx(),如果需求 不明确,建议都写。

问4:封装指的就是 私有,这句话对吗?

答:不对,因为我们常用的函数也是封装的一种体现.

好处:    

1.提高代码的安全性.         通过 私有化 实现的。    

2.提高代码的复用性.         通过 函数 实现的。

弊端:

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


网站公告

今日签到

点亮在社区的每一天
去签到