Python面向对象-接口与封装
为何要使用接口
1、接口提取了一群类共同的函数,可以把接口当做一个函数的集合。然后让子类去实现接口中的函数。
2、这么做的意义在于归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样,主要有以下几点:
- 让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。
- 归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合,而不用关心其内部的实现方式,提供相同的调用接口。
python 中接口的实现
在python中根本就没有一个叫做interface的关键字,如果非要去模仿接口的概念,一般有两种方式实现。
1、可以借助第三方模块:
http://pypi.python.org/pypi/zope.interface
twisted的twisted\internet\interface.py里使用zope.interface
文档https://zopeinterface.readthedocs.io/en/latest/
设计模式:https://github.com/faif/python-patterns
2、使用抽象类:抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。使用abc模块来实现抽象类。
import abc #利用abc模块实现抽象类
class All_file(metaclass=abc.ABCMeta):
all_type='file'
@abc.abstractmethod #定义抽象方法,无需实现功能
def read(self):
'子类必须定义读功能'
pass
@abc.abstractmethod #定义抽象方法,无需实现功能
def write(self):
'子类必须定义写功能'
pass
class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('文本数据的读取方法')
def write(self):
print('文本数据的读取方法')
class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('硬盘数据的读取方法')
def write(self):
print('硬盘数据的读取方法')
抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
多态
1.增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
2.增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
封装
当我们需要对内中的函数和变量进行隐藏,不暴露函数和变量信息给外部对象,而只是提供特定的调用接口时,我们就会使用封装。
1、在类中使用 __
开头的(不包含__
结尾)变量和函数,只能在类的内部调用,外部对象无法调用,这样就实现了内部函数变量的隐藏:
class A:
__n=123 # __ 开头的变量和函数外部对象无法访问。
def __init__(self,name):
self.__Name=name
def __f1(self):
print('f1')
def f2(self):
self.__f1()
注意:
1、这种隐藏只是一种语法上的变形操作,并不会将属性真正隐藏起来。使用__dict__
函数可以查看到其具体的命名空间(其实是在原来的基础上重命名为_类名__变量/函数名
),对象依然可以访问到。
2、这种语法级别的变形,在类定义阶段发生的,并且只在类定义阶段发生。定义之后就不会发生变形了
3、在子类定义的__x不会覆盖在父类定义的_x,因为子类中变形成了:子类名_x,而父类中变形成了:父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
2、封装数据:将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。
3、封装方法:目的是隔离复杂度
静态属性
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
class People:
def __init__(self,name,weight,height):
self.name=name
self.weight=weight
self.height=height
@property
def bmi(self):
return self.weight / (self.height**2)
p1=People('egon',75,1.85)
print(p1.bmi) #调用的时候不使用bim()的方式执行,像访问数据属性一样访问函数值
使用property的好处:将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则。
反射
自省也称作反射,这个性质展示了某对象是如何在运行期取得自身信息的。如果传一个对象给你,你可以查出它有什么能力,这是一项强大的特性。如果Python不支持某种形式的自省功能,dir和type内建函数,将很难正常工作。还有那些特殊属性,像dict,name及doc