多态
一.定义
多态: 有不同的类实例化得到的对象, 调用不同的方法, 执行的逻辑不同.
类的继承有两层意义: 1. 改变, 2. 扩展. 多态就是类的两层意义的一个具体的实现机制, 即: 调用不同的类实例化的对象下的相同方法, 实现的过程不一样.
一.封装
封装可以理解为一个多功能的自助饮料机器, 且机器是不透明密封的, 只在下方开了不同的龙头, 当顾客需要不同的饮料时, 只需要去打开不同的龙头开关即可得到自己想要的饮料, 但顾客不知道机器内部是产生不同的饮料的.
在 python 中, 封装可以是类, 可以是函数. 封装是将数据或属性隐藏在内部, 不让外部看到.
二.封装的使用
类的封装两个层面, 第一个层面的封装: 类就是一个容器, 这本身就是一种封装; 第二个层面的封装: 类中定义私有的属性, 只在类的内部使用, 外部无法访问.
Python 中不依赖语言特征去实现第二个层面的封装, 而是通过遵守一定的数据属性和函数属性的命名约定来达到封装的效果.
约定 1. 任何以双下划线开头的名字都应该是类内部私有的属性, 外部无法访问. 如下图:
这是调用类私有的数据属性, 如果调用类私有的函数属性呢? 结果见下图:
从上面的例子, 我们可以发现: 类中双下划线命名的所有属性 (包含: 数据属性和函数属性) 在外部均不能正常访问.
那么外部是不是真的就不能访问内部的数据属性呢? 我们先打印类的属性字典, 此时会发现类中的以双下划线开头的 leadteacher 数据属性和 activy 均发生了改变, 如下图所示:
至此我们发现: 此时在对应的双下划线的属性下面加上了_类名, 那么是不是就有办法在外部来进行访问了呢? 如下图:
总结: 以单下划线或双下划线命名的属性, 只是一种约定, 并不是说 python 一定不能访问. 实际上, python 并不会真的阻止你访问私有的属性, 模块也是这种约定.
那么, 子类继承父类后, 子类是否可以访问父类私有的属性呢? 见下图:
封装的第三个层面: 明确区分内外, 内部的实现逻辑, 外部无法知晓, 并且为封装到内部的逻辑他提供一个访问接口给外部使用(这才是真正的封装), 封装的含义就是将类内部的属性隐藏起来, 但是外部如果要使用它怎么办? 这是就用到了第三个层面的封装了, 我们可以在类的类别定义一个函数调用双下划线的属性, 这样我们通过调用这个函数就可以间接的访问类中隐藏的属性了. 改写上面的例子, 见下图:
该部分的代码块为:
- class School():
- price = 12000
- __leadteacher = "刘昌明" #双下划线开头的数据属性
- def __init__(self,name,addr,type):
- self.name = name
- self.addr = addr
- self.type = type
- def showinfo(self):
- print("%s 位于 %s, 是一所 % 大学, 学费是 %s"%(self.name,self.addr,self.type,self.price))
- def __activy(self):
- print("学校正在举办书法比赛")
- def returninfo(self): #通过类中的函数来访问隐藏的属性, 以供外部调用, 这才是真正意义上的封装
- print("这个学校的现在是 %s"%self.__leadteacher)
- self.__activy()
- # class Student(School):
- # print(School.__leadteacher)
- s1 =School("长江大学","湖北省荆州市","国立一本")
- # 直接在外部访问类的数据属性
- # print(s1.price)
- # print(s1.__leadteacher) #报错
- # print(s1._leadteacher) #报错
- # 直接在外部访问类的函数属性
- # s1.__activy() #报错
- # 打印类的属性字典
- # print(School.__dict__)
- # 再次访问类的内部属性
- # print(s1._School__leadteacher)
- # s1._School__activy()
- # student = Student()
- # 通过类中的接口函数来访问类中隐藏的属性
- s1.returninfo()
来源: http://www.bubuko.com/infodetail-2580854.html