继承 继承 多态
python中支持单继承和多继承。
在python3中,所有的类都默认继承Object类。
创建一个Hero类
class Hero:#创建一个英雄类
def __init__(self,name,level,category):#属性:名字、等级、系别
self.name=name
self.level=level
self.category=category
def run(self):
print("一个英雄要么凯旋,要么战死沙场")
def attack(self):
print("一往无前,所向披靡")
def cure(self):
print("上了战场,总要流点血")
查看Hero类的属性字典
print(Hero.__dict__)
执行结果为
{'__module__': '__main__', '__init__': <function Hero.__init__ at 0x00000000026D22F0>, 'run': <function Hero.run at 0x00000000026D2378>, 'attack': <function Hero.attack at 0x00000000026D2400>,
'cure': <function Hero.cure at 0x00000000026D2488>, '__dict__': <attribute '__dict__' of 'Hero' objects>, '__weakref__': <attribute '__weakref__' of 'Hero' objects>, '__doc__': None}
创建一个法师类Master,继承Hero
class Master(Hero):#定义一个法师类
def __init__(self,name,level,category,magic_power):#属性:名字,等级,系别,法术伤害
super().__init__(name,level,category)
self.magic_power=magic_power
查看Master类的属性字典
print(Master.__dict__)
执行结果为
{'__module__': '__main__', '__init__': <function Master.__init__ at 0x0000000002242510>, '__doc__': None}
创建一个Master类的实例
#创建Master实例
ZhugeLiang=Master("诸葛亮",18,"法师",1500)
ZhugeLiang.run()
ZhugeLiang.attack()
ZhugeLiang.cure()
执行结果为:
一个英雄要么凯旋,要么战死沙场
一往无前,所向披靡
上了战场,总要流点血
查看ZhugeLiang的属性字典
print(ZhugeLiang.__dict__)
执行结果为:
{'name': '诸葛亮', 'level': 18, 'category': '法师', 'magic_power': 1500}
我们在Master类中,并没有定义run()/attack()/cure()等方法,这些方法都是在Hero类中定义的,而Master类继承了Hero类中的属性和方法。
由此,我们可以推出属性访问顺序为:实例字典————>类字典---->父类字典
思考这样一个问题,假设子类和父类中存在同名的属性和方法时,我们又该如何在子类中调用父类的方法呢?
我们在Master类中定义一个run方法:
class Master(Hero):#定义一个法师类
def __init__(self,name,level,category,magic_power):#属性:名字,等级,系别,法术伤害
super().__init__(name,level,category)
self.magic_power=magic_power
def run(self):#定义一个与父类同名的run方法
def run(self):#定义一个与父类同名的run方法
super().run()
print("哈哈哈哈,你追不上我吧,哈哈哈哈,没有办法,我就是这么强大")
ZhugeLiang=Master("诸葛亮",18,"法师",1500)
ZhugeLiang.run()
执行上述代码,结果为:
一个英雄要么凯旋,要么战死沙场
哈哈哈哈,你追不上我吧,哈哈哈哈,没有办法,我就是这么强大
从执行结果可以看出,我们可以在子类中通过 super().父类方法 调用到父类中的方法。
除此之外,我们还可以直接通过 父类名.父类方法 去调用父类中的方法
class Master(Hero):#定义一个法师类
def __init__(self,name,level,category,magic_power):#属性:名字,等级,系别,法术伤害
Hero.__init__(self,name,level,category)
self.magic_power=magic_power
def run(self):#定义一个与父类同名的run方法
Hero.run(self)
print("哈哈哈哈,你追不上我吧,哈哈哈哈,没有办法,我就是这么强大")
这段代码与上面super()方法实现的功能一致,但观察后我们发现
通过super()方法调用父类方法时,方法中不用再添加self参数,但是通过父类名.父类方法的方式,必须传入一个self参数
我们可以这样理解,通过super().方法名 的方法调用父类中的方法时,会自动传入一个实例对象。
python中的继承顺序
我们前面说过python中支持多继承,那他们之间的继承顺序又是怎样的呢?
在python中,继承的查找顺序为广度优先。
class A:
def greet(self):
print("A")
class B(A):
def greet(self):
print("B")
class C(A):
def greet(self):
print("C")
class D(B):
def greet(self):
print("D")
class E(C):
def greet(self):
print("E")
class F(D,E):
def greet(self):
print("F")
me=F()
me.greet()
print(F.__mro__)
执行结果为
F
(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
![](https://images2018.cnblogs.com/blog/1406021/201805/1406021-20180531204149845-883811303.png)
python中的多态
多态是指一类事物有多种形态(多态的概念依赖与继承)
class Animal:
def eat(self):
print("天大地大,吃饭最大")
def sleep(self):
print("人生三大快事,吃饭、睡觉、打豆豆")
class Panda(Animal):
def eat(self):
print("老子可是功夫熊猫,超凶哒,我最喜欢吃小笋")
def sleep(self):
print("知道我为什么这么胖吗,因为我睡的时间长啊")
class Tiger(Animal):
def eat(self):
print("老子可不是吃素的,不然,我为什么能是百兽之王")
def sleep(self):
print("黑夜是我最好的掩护")
class Dog(Animal):
def eat(self):
print("我最喜欢吃的是骨头")
def sleep(self):
print("我一边睡觉了,一边看门")
Animal可以有多种形态,可以是Panda,可以是Tiger,也可以是Dog
多态的好处就是,当我们需要传递更多的子类,例如Cat,Pig,Bird类时,我们只需要传入一个Animal类就好了。
python中的封装
封装数据的主要目的就是为了保护数据
封装其实分为两个层面:
1.创建类和对象时分别会创建两者的名称空间,我们只能通过类名.属性名 或者对象.属性名的方式去访问,这本身就是一种封装。(对于这一层面的封装,类名.属性名、对象名.属性名就是访问隐藏属性的接口)
2.把类中的某些属性和方法隐藏起来,定义成私有的,只在类的内部使用,外部无法访问,或者只留下少量接口提供给外部访问类的内部数据
在python中,私有属性或者方法,可以在属性、方法名前加上双下划线。也就是说,我们可以通过双下划线的方式实现隐藏属性,把属性设置成私有的。
类中所有双下划线开头的名称如__x都会自动变成:__类名__x的形式
class Demo:
__x=10
def __init__(self,name,age):
self.__name=name
self.__age=age
def __test(self):
print("just try try")
d=Demo("刘亦菲",18)
print(d.__name)
print(d.__age)
d.__test()
执行上面代码,执行结果为:
Traceback (most recent call last):
File "F:/python/stuDemo/002.py", line 11, in <module>
print(d.__name)
AttributeError: 'Demo' object has no attribute '__name'
当我们使用下面的方式调用类的私有属性和方法时
print(d._Demo__name)
print(d._Demo__age)
d._Demo__test()
执行结果为
刘亦菲
18
just try try
其实我们可以这样理解,这种封装其实也就是内部帮我们改变了属性和方法的名字,将__属性名变成了__类名__属性名。这种变形的过程只是在类定义的过程中发生一次,在定义后添加属性,则不会发生凝固变形。
eg:
class Demo:
__x=10
def __init__(self,name,age):
self.__name=name
self.__age=age
def __test(self):
print("just try try")
d=Demo("刘亦菲",18)
Demo.__y=20
print(d.__y)
执行上面的代码,运行结果为:
20
这种机制也并没有从真正意义上限制我们从外部直接访问属性,知道了类名和属性名,我们依然可以通过 __类名__属性名 的方式访问到类的私有属性
在继承中,父类如果不想让子类覆盖自己的方法,就需要把方法定义为私有的。
在我身后,微笑地活下去吧。