案例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'
错误分析
为什么提示
_Wangjianlin__post?
是因为父类的__post属性有两个下划线,在python解释器中改成_Wangjianlin__post为什么会提示
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() 方法
