Python面向对象2-继承-单继承、多继承、多层继承、重写、super、私有属性方法

目标

  • 继承的概念
  • 单继承
  • 多继承
  • 子类重写父类的同名属性和方法
  • 子类调用父类的同名属性和方法
  • 多层继承
  • super()
  • 私有属性和私有方法

一. 继承的概念

生活中的继承,一般指的是子女继承父辈的财产。

  • 拓展1:经典类或旧式类

不由任意内置类型派生出的类,称之为经典类。 [经典类 甚至连Object父类都没有了]

class 类名:
    代码
    ......
  • 拓展2:新式类
class 类名(object):
  代码

区别:

Python中类分两种:旧式类和新式类:
新式类都从object继承,经典类不需要。
新式类的MRO(method resolution order 基类搜索顺序)算法采用C3算法广度优先搜索,而旧式类的MRO算法是采用深度优先搜索
新式类相同父类只执行一次构造函数,经典类重复执行多次。

Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法,具体如下:

# 父类A
class A(object):
    def __init__(self):
        self.num = 1

    def info_print(self):
        print(self.num)

# 子类B
class B(A):
    pass


result = B() # 继承了父类A的所有方法
result.info_print()  # 1

在Python中,所有新式类默认继承object类object类是顶级类或基类;其他子类叫做派生类。

二. 单继承

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

分析:徒弟是不是要继承师父的所有技术?

# 1. 师傅类
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 2. 徒弟类
class Prentice(Master):
    pass

# 3. 创建对象 daqiu
daqiu = Prentice()
# 继承了师傅的方法
daqiu.make_cake()  # 运用[古法煎饼果子配方]制作煎饼果子

三. 多继承 [python又支持多继承了]

故事推进:daqiu 是个爱学习的好孩子,想学习更多的煎饼果子技术,于是,在百度搜索,报班学习煎饼果子技术。

所谓多继承意思就是一个类同时继承了多个父类。

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

    def sayPlay(self):
        print("老师傅独有技能:唱戏曲")

class School(object):
    def __init__(self):
        self.kongfu = '[武大煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

    def findWork(self):
        print('学校独有技能:找工作')



class Prentice(School,Master): # 多继承 同时继承2个类
    pass

daqiu = Prentice()
# 先是两位老师傅那分别学的独家技能
daqiu.sayPlay()
daqiu.findWork() 

# 再是共同的技能
daqiu.make_cake() # 默认使用第一个父类的同名属性和方法

在这里插入图片描述

注意:当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法。

四. 子类重写父类同名方法和属性

故事:daqiu掌握了师父和培训的技术后,自己潜心钻研出自己的独门配方的一套全新的煎饼果子技术。

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(object):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


# 独创配方
class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake()

# 为了方便且快速地看清继承关系和顺序,可以用__mro__方法来获取这个类的调用顺序。
print(Prentice.__mro__)

在这里插入图片描述

子类和父类具有同名属性和方法,默认使用子类的同名属性和方法。(重写了嘛 当然是啦 就近 更近)
为了方便且快速地看清继承关系和顺序,可以用__mro__方法来获取这个类的调用顺序。

五. 子类调用父类的同名方法和属性

比较麻烦,要专门写一个方法调用
只是记得可以调就是了

故事:很多顾客都希望也能吃到古法和黑马的技术的煎饼果子。

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

class School(object):
    def __init__(self):
        self.kongfu = '[武大煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 重写了 如何还能调用父类方法呢
class Prentice(School,Master):
    def __init__(self):
        self.kongfu = '{独创煎饼果子配方}'

    # 重写父类方法
    def make_cake(self):
        # 如果是先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化
        # ★ 不加此行 调用了下面的的方法后 再调用这个方法就会有问题  kongfu的值会被频繁的改
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    # 调用父类方法,但是为了保证调用的也是父类的属性,必须在调用方法前调用父类的初始化
    def make_master_cake(self):
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)


# Master.make_cake() # 外面可以直接调 但是报错 因为没有对象啊

daqiu = Prentice()
daqiu.make_cake()
daqiu.make_master_cake()
daqiu.make_school_cake()
# 对象.方法() 会自动将当前对象当作self传进去

daqiu.make_cake() # self.kongfu还是保持School的

对象.方法() 会自动将当前对象当作self传进去

在这里插入图片描述

六. 多层继承

故事:N年后,daqiu老了,想要把所有技术传承给自己的徒弟。

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(object):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'

    def make_cake(self):
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    def make_master_cake(self):
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)


# 徒孙类
class Tusun(Prentice):
    pass


xiaoqiu = Tusun()

xiaoqiu.make_cake()

xiaoqiu.make_school_cake()

xiaoqiu.make_master_cake()

在这里插入图片描述

七. super()调用父类方法

继承关系: Master->School->Prentice (爷->父->儿)
场景: Master有make_cake方法,School重写了make_cake方法,Prentice又重写了make_cake方法
目前有3个make_cake方法 我想在Prentice类里面同时能调用到这3个make_cake方法,怎么做呢?

方法一:原始笨方法

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(Master):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

class Prentice(School):
    def __init__(self):
        self.kongfu = '[独创煎饼果子技术]'

    def make_cake(self):
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    # 代码在这  前面都直接复制的,一样(唯一改了一个继承关系: School(Master):)
    # 一次性调用父类的同名属性和方法
    def make_old_cake(self):
        # 方法一:代码冗余;父类类名如果变化,这里代码需要频繁修改
        # 分别调用两次init和两次对应方法
        Master.__init__(self)
        Master.make_cake(self)
        School.__init__(self)
        School.make_cake(self)

daqiu = Prentice()
daqiu.make_old_cake()

在这里插入图片描述

方法二:super带参写法

好多了 但非最佳, 也不是很推荐

注意:使用super() 可以自动查找父类。调用顺序遵循 __mro__ 类属性的顺序。比较适合单继承使用。
super指的是直接父类 (子的super=父,父的super=爷)

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(Master):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

        # 为了能逐级调用到父类的方法 这里必须super调用一下
        # 方法2: super带参 这里也要加代码
        super(School,self).__init__()
        super(School,self).make_cake()


class Prentice(School):
    def __init__(self):
        self.kongfu = '[独创煎饼果子技术]'

    def make_cake(self):
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    # 本节代码在这: 一次性调用父类的同名属性和方法
    def make_old_cake(self):
        # 方法二: super
        # 方法2 带参写法: super(当前类名,self).函数
        super(Prentice,self).__init__()
        super(Prentice,self).make_cake() # 运用[黑马煎饼果子配方]制作煎饼果子
        # 确实调用到了父类 但是只调用到了爸爸,没有调用到爷爷
        # 怎么办呢? 答: 爸爸方法里也要这么写一份  (我的super是爸爸,爸爸的super才是爷爷  super是直接父类)


daqiu = Prentice()
daqiu.make_old_cake()

在这里插入图片描述

方法三:super无参写法 (推荐、以后的写法)

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(Master):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

        # 方法3 父类要加的代码  就是每个子类都主动调用一下父类的该方法即可
        super().__init__()
        super().make_cake()

class Prentice(School):
    def __init__(self):
        self.kongfu = '[独创煎饼果子技术]'

    def make_cake(self):
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    # 方法三: 无参super
    def make_old_cake(self):
        super().__init__()
        super().make_cake()



daqiu = Prentice()
daqiu.make_old_cake()

在这里插入图片描述

注意:使用super() 可以自动查找父类。调用顺序遵循 __mro__ 类属性的顺序。比较适合单继承使用。
super指的是直接父类 (子的super=父,父的super=爷)

八. 私有权限

8.1 定义私有属性和方法

在Python中,可以为实例属性和方法设置私有权限,即设置某个实例属性或实例方法不继承给子类。

故事:daqiu把技术传承给徒弟的同时,不想把自己的钱(2000000个亿)继承给徒弟,这个时候就要为这个实例属性设置私有权限。

设置私有权限的方法:在属性名和方法名 前面 加上两个下划线 __。
不愧是python 命名规则就是私有属性的语法

class Father(object):
    def __init__(self):
        self.kongfu = '[独创热干面配方]'
        # 定义私有属性
        self.__money = 2000000

    # 定义私有方法
    def __info_print(self):
        print(self.kongfu)
        print(self.__money)

    def make_cake(self):
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

class Son(Father):
    def print_info(self):
        print(self.kongfu) # 能继承到的 都能正常访问 但一定得"对象.xx"的形式 因为都属于对象
        self.make_cake()
        # self.__money # 报错 私有的怎么也访问不到
        # self.__info_print() # 报错 私有的怎么也访问不到


fa = Father()
#print(fa.__money)  # AttributeError: 'Father' object has no attribute '__money'
#fa.__info_print  # AttributeError: 'Father' object has no attribute '__info_print'
#结论: 私有属性和私有方法都不能在类外访问

## 非私有属性方法才可以正常访问
print(fa.kongfu)
fa.make_cake()


son = Son()
# print(son.__money) # AttributeError: 'Son' object has no attribute '__money'
# son.__info_print() # AttributeError: 'Son' object has no attribute '__info_print'
#结论: 私有属性和私有方法 肯定不会被继承的

# 非私有属性和方法 才可以正常被继承
print(son.kongfu)
son.make_cake()

注意:私有属性和私有方法只能在类里面访问和修改。

8.2 获取和修改私有属性值

在Python中,一般定义函数名get_xx用来获取私有属性,定义set_xx用来修改私有属性值。


class Prentice(object):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'
        self.__money = 2000000

    # 获取私有属性
    def get_money(self):
        return self.__money # 和java一样 利用私有属性只能在类内访问这一特点

    # 修改私有属性
    def set_money(self,money):
        self.__money = money # 和java一样 利用私有属性只能在类内访问这一特点


    def __info_print(self):
        print(self.kongfu)
        print(self.__money)

    def make_cake(self):
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')


# 徒孙类
class Tusun(Prentice):
    pass

xq = Tusun()
# 私有属性用访问器访问
print(xq.get_money()) # 2000000
xq.set_money(10)
print(xq.get_money()) # 10

# 非私有属性正常访问
print(xq.kongfu) # [独创煎饼果子配方]
xq.kongfu= '[独创热干面配方]'
print(xq.kongfu) # [独创热干面配方]
# print(Prentice.kongfu) # type object 'Prentice' has no attribute 'kongfu'
                        # 都是非静态的成员 属于对象 而不属于类


在这里插入图片描述

九. 总结

  • 继承的特点

    • 子类默认拥有父类的所有属性和方法
    • 子类重写父类同名方法和属性
    • 子类调用父类同名方法和属性
  • super()方法快速调用父类方法

  • 私有权限

    • 不能继承给子类的属性和方法需要添加私有权限
    • 语法
    class 类名():
      # 私有属性
      __属性名 =# 私有方法
      def __函数名(self):
        代码
    

小笔记:

对象.方法() 会自动将当前对象当作self传进去

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值