python面向对象-继承与super()方法(高级)

案例1

实现父类 WangJianLin

定义类

class WangJianLin:
    def __init__(self):
        print("WangJianLin的init()方法")
        # 定义name,是公共属性,类外、类内都能使用
        self.name="王健林"
        # 定义money,1000亿,以 _ 开头,是程序员之间的约定,在类内部、子类中使用,不要在类外部使用
        self._money=1000
        # 定义职务post,不是世袭制,不能被子类继承,是私有的,所以前面有两个下划线
        self.__post="万达董事长"

    def say(self):
        # 自我介绍
        print("我是%s,职务是%s,我有人民币 %d 元"%(self.name,self.__post,self._money))

创建对象 wjl,并调用 say() 方法:

wjl = WangJianLin()
wjl.say()

执行结果:

WangJianLin的init()方法
我是王健林,职务是万达董事长,我有人民币 1000 元

实现子类 WangSiCong

定义类:

class WangSiCong(WangJianLin):
    pass

创建对象并访问属性、调用方法:

wsc = WangSiCong()
# 继承父类公共属性
print("wsc.name:",wsc.name) 
# 继承父类以 _ 开头的属性。程序员之间的约定,不要在类外部使用
print("wsc._money:",wsc._money) 
# print("wsc.__post:",wsc.__post) # 不能继承父类以 __ 开头的属性
wsc.say() # 继承父类的实例方法

执行结果:

WangJianLin的init()方法  -- 创建子类对象,自动调用父类的 init() 方法
wsc.name: 王健林   -- 打印王健林是因为继承父类的实例属性
wsc._money: 1000
我是王健林,职务是万达董事长,我有人民币 1000 元  -- 通过父类的 say() 方法可以访问职务post

提出问题

执行下面代码时:

# 通过子类对象调用 say() 方法
wsc.say()

父类的 say() 方法中,self 是哪个对象?

修改代码如下:

def say(self):
    # 自我介绍
    print("我是%s,职务是%s,我有人民币 %d 元"%(self.name,self.__post,self._money))
    print("say() 中的self:",self) # 改动的代码

执行结果:

say() 中的self: <__main__.WangSiCong object at 0x000001DD55304C40>

说明:虽然 say() 是 WangJianLin 的方法,但由于是通过 WangSiCong 对象调用的,所以 self 是 WangSiCong 对象

提出问题

执行 wsc.say() 方法时,显示如下:

我是王健林,职务是万达董事长,我有人民币 1000 元

错误:

  • 名字继承父类,是不合理的

解决

在 WangSiCong 类中定义 __init__() 方法,初始化 name 属性

class WangSiCong(WangJianLin):
    def __init__(self):
        print("WangSiCong 的 init() 方法")
        # 初始化name
        self.name="王校长"

使用:

wsc = WangSiCong()

print("wsc.name:",wsc.name)

执行结果:

WangSiCong 的 init() 方法
wsc.name: 王校长

总结

当子类定义 __init__() 方法后,创建对象时,就只调用该 __init__() 方法后,不再调用 父类的 __init__() 方法

访问 _money 报错

print("wsc._money:",wsc._money)

执行报错:

AttributeError: 'WangSiCong' object has no attribute '_money'

错误分析

通过子类 WangSiCong 创建对象时,只调用子类的 __init__() 方法,该方法中,没有定义 _money 属性

先不解决该问题

调用 say() 报错

执行下面代码:

wsc.say()

报错:

AttributeError: 'WangSiCong' object has no attribute '_WangJianLin__post'

错误分析

  1. 为什么提示_Wangjianlin__post?
    是因为父类的 __post 属性有两个下划线,在python解释器中改成 _Wangjianlin__post

  2. 为什么会提示no attribute,没有这个属性
    父类的 say() 方法里调用了 __post 属性,由于子类实现 __init__() 方法后,创建对象时,只调用子类的 __init__() 方法,该方法中,没有定义 __post 属性

解决

为解决上面的问题,在 子类 的 __init__() 方法中,调用 父类 的 __init__() 方法,这样就能对 _money、__post 属性进行初始化。

方式一:通过 super()方法调用

class WangSiCong(WangJianLin):
    def __init__(self):
        # 调用父类的__init__()方法
        super().__init__()
        # 定义name属性
        self.name="王校长"

显示结果如下:

WangSiCong 的 init() 方法
WangJianLin的init()方法
wsc.name: 王校长
wsc._money: 1000
我是王校长,职务是万达董事长,我有人民币 1000 元

方式二:通过父类名调用

还可以通过 父类名 调用 __init__(self)

注意:需要传入 self

class WangSiCong(WangJianLin):
    def __init__(self):
        print("WangSiCong 的 init() 方法")
        # 调用父类的__init__()方法
        WangJianLin.__init__(self)
        # 定义name属性
        self.name="王校长"

提出问题

职务还是错误的

分析

为了能够正确显示职务,只能重新实现父类的say(),因为父类的say()方法调用的父类的私有变量__post

子类 无法修改 父类的私有变量(不准通过_Wangjianlin__post修改,不符合规范)

概念:覆盖父类的方法

当子类重新实现父类的方法时,就称之为:子类覆盖父类的方法

解决

class WangSiCong(WangJianLin):
    def __init__(self):
        # 调用父类的__init__()方法
        super().__init__()
        # 继承父类的属性
        self.name="王校长"
        # 定义__post属性
        self.__post="校长"

    def say(self):
        print("我是%s,职务是%s,我有人民币 %d 元"%(self.name,self.__post,self._money))

显示结果如下:

WangSiCong 的 init() 方法
WangJianLin的init()方法
wsc.name: 王校长
wsc._money: 1000
我是王校长,职务是校长,我有人民币 1000 元

练习

类 WangJianLin 定义 buy() 方法,只能买 公司、地皮
类 WangSiCong 可以随便花钱买,重新实现 buy() 方法


原文出处:/show_1EF2ClIatxUJ.html