Python学习日记(初级篇02面向对象之继承)——黑马程序员视频学习笔记

Python面向对象2/4--继承

  • 一、继承的概念
  • 二、单继承
  • 三、多继承
  • 四、子类重写父类同名方法和属性
  • 五、子类调用父类的同名方法和属性(复杂)
  • 六、多层继承
  • 七、super()调用父类方法
  • 八、私有权限
    • 8.1定义私有属性和方法

一、继承的概念

  • 在程序中,继承描述的是多个类之间的所属关系。
  • 如果一个类A里面的属性和方法可以复用,则可以通过继承的方式,传递到类B里。那么类A就是基类,也叫做父类;类B就是派生类,也叫做子类。

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

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

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


# 子类B
class B(A):
    pass


result = B()
result.info_print()  # 1

二、单继承

  • 单继承:子类只继承一个父类
# 定义一个Master类
class Master(object):
    def __init__(self):
        # 属性
        self.kongfu = "古法煎饼果子配方" 

    # 实例方法
    def make_cake(self):
        print("按照 <%s> 制作了一份煎饼果子..." % self.kongfu)


# 定义Prentice类,继承了 Master,则Prentice是子类,Master是父类。
class Prentice(Master):
    # 子类可以继承父类所有的属性和方法,哪怕子类没有自己的属性和方法,
    # 也可以使用父类的属性和方法。
    pass


damao = Prentice()  # 创建子类实例对象
print(damao.kongfu)  # 子类对象可以直接使用父类的属性
damao.make_cake()  # 子类对象可以直接使用父类的方法

三、多继承

  • 多继承:子类继承多个父类
  • 子类的魔法属性__mro__决定了属性和方法的查找顺序

说明:

1.多继承可以继承多个父类,也继承了所有父类的属性和方法。

2.注意:如果多个父类中有同名的 属性和方法,则默认使用第一个父类的属性和方法(根据类的魔法属性mro的顺序来查找)。

3.多个父类中,不重名的属性和方法,不会有任何影响。

class Master(object):
    def __init__(self):
        self.kongfu = "古法煎饼果子配方"  # 实例变量,属性

    def make_cake(self):                    # 实例方法,方法
        print("[古法] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)

    def dayandai(self):
        print("师傅的大烟袋..")


class School(object):
    def __init__(self):
        self.kongfu = "现代煎饼果子配方"

    def make_cake(self):
        print("[现代] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)

    def xiaoyandai(self):
        print("学校的小烟袋..")


class Prentice(Master, School):
    # 多继承,继承了多个父类(Master在前)
    pass


damao = Prentice()
print(damao.kongfu)  # 执行Master的属性
damao.make_cake()  # 执行Master的实例方法

# 子类的魔法属性__mro__决定了属性和方法的查找顺序
print(Prentice.__mro__)

damao.dayandai()  # 不重名不受影响
damao.xiaoyandai()

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

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

    def make_cake(self):
        print("[古法] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)


class School(object):
    def __init__(self):
        self.kongfu = "现代煎饼果子配方"

    def make_cake(self):
        print("[现代] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)


class Prentice(School, Master):  # 多继承,继承了多个父类
    def __init__(self):
        self.kongfu = "猫氏煎饼果子配方"

    def make_cake(self):
        print("[猫氏] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)


# 如果子类和父类的方法名和属性名相同,则默认使用子类的
# 叫 子类重写父类的同名方法和属性
damao = Prentice()
print(damao.kongfu)  # 子类和父类有同名属性,则默认使用子类的
damao.make_cake()  # 子类和父类有同名方法,则默认使用子类的

# 子类的魔法属性__mro__决定了属性和方法的查找顺序
print(Prentice.__mro__)
# (, ,
# , )

五、子类调用父类的同名方法和属性(复杂)

  • 无论何时何地,self都表示是子类的对象。在调用父类方法时,通过传递self参数,来控制方法和属性的访问修改。
class Master(object):
    def __init__(self):
        self.kongfu = "古法煎饼果子配方"  # 实例变量,属性

    def make_cake(self):                    # 实例方法,方法
        print("[古法] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)


class School(object):
    def __init__(self):
        self.kongfu = "现代煎饼果子配方"

    def make_cake(self):
        print("[现代] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)


class Prentice(School, Master):  # 多继承,继承了多个父类
    def __init__(self):
        self.kongfu = "猫氏煎饼果子配方"

    def make_cake(self):
        print("执行子类的__init__方法前,self.kongfu属性:%s" % self.kongfu)
        self.__init__()  # 执行本类的__init__方法,做属性初始化 self.kongfu = "猫氏...."
        print("执行子类的__init__方法前,self.kongfu属性:%s" % self.kongfu)
        print("[猫氏] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)

    # 调用父类方法格式:父类类名.父类方法(self)
    def make_old_cake(self):
        # 不推荐这样访问父类的实例属性,相当于创建了一个新的父类对象
        # print("直接调用Master类的kongfu属性:%s" % Master().kongfu)

        # 可以通过执行Master类的__init__方法,来修改self的属性值
        print("执行Master类的__init__方法前,self.kongfu属性:%s" % self.kongfu)
        Master.__init__(self)  # 调用了父类Master的__init__方法 self.kongfu = "古法...."
        print("执行Master类的__init__方法后,self.kongfu属性:%s" % self.kongfu)
        Master.make_cake(self)  # 调用父类Master的实例方法

    def make_new_cake(self):
        # 不推荐这样访问类的实例属性,相当于创建了一个新的父类对象
        # print("直接调用School类的kongfu属性:%s" % School().kongfu)

        # 可以通过执行School类的__init__方法,来修改self的属性值
        print("执行School类的__init__方法前,self.kongfu属性:%s" % self.kongfu)
        School.__init__(self)  # 调用了父类School的__init__方法 self.kongfu = "现代...."
        print("执行School类的__init__方法后,self.kongfu属性:%s" % self.kongfu)
        School.make_cake(self)  # 调用父类School的实例方法


# 实例化对象,自动执行子类的__init__方法
damao = Prentice()

damao.make_cake()  # 调用子类的方法(默认重写了父类的同名方法)

print("--" * 10)
damao.make_old_cake()  # 进入实例方法去调用父类Master的方法

print("--" * 10)
damao.make_new_cake()  # 进入实例方法去调用父类School的方法

print("--" * 10)
damao.make_cake()  # 调用本类的实例方法
# 执行子类的__init__方法前,self.kongfu属性:猫氏煎饼果子配方
# 执行子类的__init__方法前,self.kongfu属性:猫氏煎饼果子配方
# [猫氏] 按照 <猫氏煎饼果子配方> 制作了一份煎饼果子...
# --------------------
# 执行Master类的__init__方法前,self.kongfu属性:猫氏煎饼果子配方
# 执行Master类的__init__方法后,self.kongfu属性:古法煎饼果子配方
# [古法] 按照 <古法煎饼果子配方> 制作了一份煎饼果子...
# --------------------
# 执行School类的__init__方法前,self.kongfu属性:古法煎饼果子配方
# 执行School类的__init__方法后,self.kongfu属性:现代煎饼果子配方
# [现代] 按照 <现代煎饼果子配方> 制作了一份煎饼果子...
# --------------------
# 执行子类的__init__方法前,self.kongfu属性:现代煎饼果子配方
# 执行子类的__init__方法前,self.kongfu属性:猫氏煎饼果子配方
# [猫氏] 按照 <猫氏煎饼果子配方> 制作了一份煎饼果子...
#
# 进程已结束,退出代码0

六、多层继承

class Master(object):
    def __init__(self):
        self.kongfu = "古法煎饼果子配方"  # 实例变量,属性

    def make_cake(self):  # 实例方法,方法
        print("[古法] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)


class School(object):
    def __init__(self):
        self.kongfu = "现代煎饼果子配方"

    def make_cake(self):
        print("[现代] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)


class Prentice(School, Master):  # 多继承,继承了多个父类
    def __init__(self):
        self.kongfu = "猫氏煎饼果子配方"

    def make_cake(self):
        print("执行子类的__init__方法前,self.kongfu属性:%s" % self.kongfu)
        self.__init__()  # 执行本类的__init__方法,做属性初始化 self.kongfu = "猫氏...."
        print("执行子类的__init__方法前,self.kongfu属性:%s" % self.kongfu)
        print("[猫氏] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)

    # 调用父类方法格式:父类类名.父类方法(self)
    def make_old_cake(self):
        # 不推荐这样访问父类的实例属性,相当于创建了一个新的父类对象
        # print("直接调用Master类的kongfu属性:%s" % Master().kongfu)

        # 可以通过执行Master类的__init__方法,来修改self的属性值
        print("执行Master类的__init__方法前,self.kongfu属性:%s" % self.kongfu)
        Master.__init__(self)  # 调用了父类Master的__init__方法 self.kongfu = "古法...."
        print("执行Master类的__init__方法后,self.kongfu属性:%s" % self.kongfu)
        Master.make_cake(self)  # 调用父类Master的实例方法

    def make_new_cake(self):
        # 不推荐这样访问类的实例属性,相当于创建了一个新的父类对象
        # print("直接调用School类的kongfu属性:%s" % School().kongfu)

        # 可以通过执行School类的__init__方法,来修改self的属性值
        print("执行School类的__init__方法前, \
        self.kongfu属性:%s" % self.kongfu)
        School.__init__(self)  # 调用了父类School的__init__方法 self.kongfu = "现代...."
        print("执行School类的__init__方法后,self.kongfu属性:%s" % self.kongfu)
        School.make_cake(self)  # 调用父类School的实例方法


class Tusun(Prentice):
    pass


xiaoqiu = Tusun()
xiaoqiu.make_cake()
xiaoqiu.make_old_cake()
xiaoqiu.make_new_cake()

七、super()调用父类方法

子类继承了多个父类,如果父类类名修改了,那么子类也要涉及多次修改。而且需要重复写多次调用,显得代码臃肿。

使用super() 可以逐一调用所有的父类方法,并且只执行一次。调用顺序遵循 mro 类属性的顺序。

注意☆☆☆☆☆:如果继承了多个父类,且父类都有同名方法,则默认只执行第一个父类的(同名方法只执行一次,目前super()不支持执行多个父类的同名方法)

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

    def make_cake(self):
        print('[古法]按照<%s>制作了一份煎饼果子' % self.kungfu)


class School(Master):
    def __init__(self):
        self.kungfu = '现代煎饼果子配方'

    def make_cake(self):
        # super()带参数版本
        super(School, self).__init__()
        super(School, self).make_cake()
        print('[现代]按照<%s>制作了一份煎饼果子' % self.kungfu)


class Prentice(School, Master):
    def __init__(self):
        self.kungfu = '自创煎饼果子配方'

    def make_cake(self):
        self.__init__()
        print('[自创]按照<%s>制作了一份煎饼果子' % self.kungfu)

    def make_all_cake(self):
        # 方式1
        School.__init__(self)
        School.make_cake(self)
        Master.__init__(self)
        Master.make_cake(self)
        self.__init__()
        self.make_cake()
        print('*' * 50)
        # 方式2
        super().__init__()
        super().make_cake()
        self.make_cake()


xiaoli = Prentice()
xiaoli.make_all_cake()
print(Prentice.__mro__)

八、私有权限

8.1定义私有属性和方法

  • 私有权限:在属性名和方法名 前面 加上两个下划线 __

1.类的私有属性 和 私有方法,都不能通过对象直接访问,但是可以在本类内部访问;

2.类的私有属性 和 私有方法,都不会被子类继承,子类也无法访问;

3.私有属性 和 私有方法 往往用来处理类的内部事情,不通过对象处理,起到安全作用。

4.Python中没有像C++中 publicprivate 这些关键字来区别公有属性和私有属性。

5.Python是以属性命名方式来区分,如果在属性和方法名前面加了2个下划线’__',则表明该属性和方法是私有权限,否则为公有权限。

你可能感兴趣的:(Python,python,学习,开发语言)