Python 面向对象编程---继承

Python 面向对象编程—封装

继承的概念

继承在生活中,指的是子女继承父辈的财产
Python中 即子类默认继承父类中的所有属性和方法,是描述的类与类之间所属关系.
父类的私有权限属性和方法也是可以继承的,区别是调用时操作不同

单继承

一个类只继承一个父类

基本语法:
class 类B(类A):
   pass

称为类 B 继承类 A
特点: B类的对象可以使用 A类的属性和方法
优点: 代码复用.重复相同的代码不用多次书写.
名词: 
   类A: 父类 		基类
   类B: 子类		派生类
:
class A:
    def __init__(self):
        self.name = '小明'

    def show(self):
        print(self.name)

class B(A):
    pass

b = B()
b.show()    # 小明

多继承

一个类同时继承了多个父类

基本语法:
class 类B(类A,类C,类D...):
   pass

称为类 B 继承类 A,C,D...
特点: B类的对象可以使用 A,C,D...类的属性和方法
:
class T(object):
    def __init__(self):
        self.zuchuan = '祖传秘方'
    def make_zuchuan(self):
        print(self.zuchuan)

class School(object):
    def __init__(self):
        self.kexue = '科学'
    def make_kexue(self):
        print(self.kexue)

class B(School,T):  
    pass

b = B()
b.make_kexue()  
b.make_zuchuan()  
# 输出:科学
#     AttributeError: 'B' object has no attribute 'zuchuan'

当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法
本例中b对象应当含有的内容为,School和T类的属性和方法,但是由于上面原因,有两个相同的init方法,所以只调用第一个父类的方法的init方法,导致b对象只含有School类的make_kexue方法,kexue属性,以及T的make_zuchuan方法,但是没有T的init方法,所以也就没有zuchuan属性,这是本例的 错误原因

修改
知道错误原因为init同名,则可以将T中的self.zuchuan定义为类属性,舍去init方法 注 有很多方法解决这个问题,这只是其中一种

class T(object):
    def __init__(self):
        self.zuchuan = '祖传秘方'
    def make_zuchuan(self):
        print(self.zuchuan)

class School(object):
    kexue = '科学'
    def make_kexue(self):
        print(self.kexue)

class B(School,T):   # 多层继承的格式
    pass

b = B()
b.make_kexue()
b.make_zuchuan()  
# 输出 科学
#     祖传秘方

一定要牢记该多继承的性质

子类重写 调用父类同名属性和方法

为了更好的发挥继承的优势,可以对子类重写和调用父类同名属性和方法,也可以在子类中添加子类独有的方法和属性

class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def show(self):
        print("我叫%s,今年%d"%(self.name,self.age))

class Teacher(Person):   # 继承Perosn,所以Teacher类中以及有了从Person继承来的__init__方法

    def show(self):   # 这是对Person类进行重写,
        print("我叫%s,今年%d,我是一名老师" % (self.name, self.age))

t = Teacher("张三",23)
t.show()
# 输出 我叫张三,今年23,我是一名老师

思考,如何在多继承中实现调用不同父类同名属性和方法呢?

C++中是通过作用域规范,进行调用不同父类相同的方法
Python中则是通过在子类中对父类进行重写方法进行调用



class Master(object):
    def __init__(self):
        self.zu = '祖传秘籍'

    def make_cake(self):
        print(self.zu)

class School(object):
    def __init__(self):
        self.kexue = '科学'

    def make_cake(self):
        print(self.kexue)

class T(School,Master):
    def __init__(self):
        self.T = '独创'

    def make_cake(self):
        print(self.T)

    def make_new_Master(self):
        Master.__init__(self)   #1 由于子类已经重写了init方法,覆盖了父类继承而来的init方法,所以想要调用父类的同名函数,则需要手动实现父类的init函数
        Master.make_cake(self)

    def make_new_School(self):
        School.__init__(self)  #2
        School.make_cake(self)


if __name__ == '__main__':
    t = T()
    t.make_cake()
    t.make_new_Master()
    t.make_new_School()
# 输出 独创 祖传秘籍 科学

思考 如果子类不重写init和make_cake方法,#1和#2处是否都要写?
不需要都写,因为当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法,可以动手试一试,但是建议都写,增加规范性,提升代码的健壮性

self的添加

  • 在类封装的方法内部,self 就表示 当前调用方法的对象自己

  • 调用方法时,程序员不需要传递 self 参数

  • 在方法内部

    • 可以通过 self. 访问对象的属性
    • 也可以通过 self. 调用其他的对象方法
  • 在类继承中,则需要明白,self在方法的括号中:如Master.make_cake(self),是为了时刻跟踪从到底是哪一个对象调用了该方法,上例中的#1和#2所属的代码块中的self都不可省略

多层继承

C类继承B类,B类继承A类,则将这种超过两次继承的类的关系称为多层继承
要理解多层继承和多继承的区别

  • 多继承是针对单继承的,表明一个类有多个父类
  • 多层继承是针对继承次数的,表明一个类至少是子类的子类
class Master(object):
    def __init__(self):
        self.zu = '祖传秘籍'

    def make_cake(self):
        print(self.zu)

class School(object):
    def __init__(self):
        self.kexue = '科学'

    def make_cake(self):
        print(self.kexue)

class T(School,Master):     # 这里杂糅了多继承和多层继承,这里是多继承
    def __init__(self):
        self.T = '独创'

    def make_cake(self):
        print(self.T)

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

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

class A(T):    # 多层继承关系
    pass

if __name__ == '__main__':
    a = A()
    a.make_cake()
    a.make_new_Master()
    a.make_new_School()

super()

子类中调用父类的方法:

  • 法1:可以用父类类名.方法名
  • 法2:用super(类名,self).方法名

举例

在多继承关系中,如何实现在孙类中调用父类和祖父类的同名方法呢?

例子:
class A(object):
    def __init__(self):
        self.name = '祖父'

    def show(self):
        print(self.name)


class B(A):
    def __init__(self):
        self.name = '父亲'
        
    def show(self):
        print(self.name)
        
class C(B):
    def __init__(self):
        self.name = '孙子'

    def show(self):
        print(self.name)

if __name__ == '__main__':
    c = C()
    c.show()  # 孙子

方法1:

添加函数
    
    def new_show(self):
        B.__init__(self)
        B.show(self)
        A.__init__(self)
        A.show(self)

if __name__ == '__main__':
    c = C()
    c.show()
    c.new_show()   # 输出 孙子 父亲 祖父

思考:当类过多时,这样写是否会十冗余?
因此引入super()方法
方法2:

在孙子类中添加super方法,在父亲类中也添加super,则有
class A(object):
    def __init__(self):
        self.name = '祖父'

    def show(self):
        print(self.name)


class B(A):
    def __init__(self):
        self.name = '父亲'

    def show(self):
        print(self.name)
        super(B,self).__init__()
        super(B, self).show()


class C(B):
    def __init__(self):
        self.name = '孙子'

    def show(self):
        print(self.name)

    def new_show(self):
        super().__init__()
        super().show()
    # def new_show(self):
    #     B.__init__(self)
    #     B.show(self)
    #     A.__init__(self)
    #     A.show(self)

if __name__ == '__main__':
    c = C()
    c.show()
    c.new_show()   # 输出 孙子 父亲 祖父

super的本质就是代替该类的父类,当父类的名字改变时,则不需要像方法1那样修改父类名称,增加了代码的健壮性,同时注意这是在孙子类和父亲类中都添加了super方法,需要好好理解为什么这样做,有利于加深理解
是否会产生这样的疑问,为什么这里没有传入self参数呢?
super有两种形式,一种是例子中的简化模式,一种是super(本类名,self).方法名,所以简化版的super可以不用写self参数,由函数自己追踪,将例子中的super().都改成super(父类名,self). 也是可以正常运行的,可以自己动手试一试

私有属性和私有方法

私有属性和私有方法,就是为类的属性和方法设置为私有权限

私有权限: 
	定义: 在方法和属性前加上两个下划线, 就变为私有.
	性质:
	1. 不能在类外部通过对象直接访问和使用, 只能在类内部访问和使用
	2. 能被子类继承,但是不能被子类和子类对象使用
公有: 不是私有的,就是公有的.

举例:性质1

class A(object):
    def __init__(self):
        self.__money = 1000
        self.name = '小明'

    def __jueji(self):
        print("这是我的独门绝技!")

class B(A):
    pass
    def show(self):
        print("我叫%s,有%d元"%(self.name,self.__money))

    def show_jueji(self):
        self.__jueji()

a = A()
print(a.name)     # 小明
print(a,__money)    #  NameError: name '__money' is not defined
a.__jueji()      # AttributeError: 'A' object has no attribute '__jueji'

举例:性质2

class A(object):
    def __init__(self):
        self.__money = 1000
        self.name = '小明'

    def __jueji(self):
        print("这是我的独门绝技!")

class B(A):
    pass
    
b = B()
print(b.name)    # 小明
print(b.__money)   # 'B' object has no attribute '__money'
b.__jueji()   # 'B' object has no attribute '__jueji'

那如何去使用这些私有属性和方法呢?
可以通过定义外部接口get,set方法进行调用

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Philo`

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值