前面,我们学习过OOP的继承,知道子类可以继承父类的特性,可以拿来用,也可以改变父类的特性变为已有,当然,我们只是学习了一种继承关系,今天,我们要重新认识一下Python的继承之
多继承
静态语言中,C++支持多继承,一个子类可以拥有多个父类,但是对于Java来说,就不行了,只能实现单继承,Java可以巧妙的利用实现多个接口(interface),内部类等来实现这种"多继承"。
动态语言中,Python是没有接口的,本身也不提供抽象类一说,为什么要像Java一样,当一个类实现一个接口的时候,它必须实现接口中声明的所有方法,否则会出错。我们的Python才不会这么设计,一方面是因为它支持多重继承,另一方面,是因为Python活泼,动,我们可以设计一个"伪接口"如下:
class interface():
pass
如果是Java的话,interface中你需要事先声明好方法体,不然,你让别人实现你接口什么呢?
但是我们的Python,可以动态给interface绑定方法甚至变量
import types
def func(*args,**others): #定义一个方法
#do something
interface.my_func = types.MethodType(func,interface) #给接口绑定一个接口方法,方法显然已被实现
i = interface() #接口实例(其实就是类,这里我们模仿接口)
i.my_func(*args,**others) #类的属性,可以被所有属于类的实例访问,因此这里我们用接口实例调用方法
看了上面的伪代码后,我们是不是觉得,接口对于Python来说意义不大?来来,我们围观一下执行结果:
不止一种?
今天虽说是讲多继承的,但是我们不得不说下,接口这个事,既然语言又不止Python一种,我们何不多花点时间多学一点呢?
抽象类
Python本身不提供抽象类,但是,我们可以借助abc模块,进行抽象类的模拟和实现(等同于Java接口的定义)
我们看下demo:
#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-
from abc import ABCMeta,abstractmethod #abc模块提供抽象类机制
class interface(metaclass = ABCMeta): #指定当前类是一个抽象类
@abstractmethod #指定抽象方法
def A(self):
pass
@abstractmethod
def B(self):
pass
i = interface()
我们猜测一下,这个抽象类能不能被实例化,也就是上述的最后一行代码可行否?我们看下,IDE给我们的答案是什么:
上述的意思,大概是,我们必须先实现抽象类interface的两个方法A和B,是必须! 下面我们定义一个类,继承这个inteface,并实现抽象方法A和B:
#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-
from abc import ABCMeta,abstractmethod #abc模块提供抽象类机制
class interface(metaclass = ABCMeta): #指定当前类是一个抽象类
@abstractmethod #指定抽象方法
def A(self):
pass
@abstractmethod
def B(self):
pass
class Implement(interface):
def A(self):
print("必须实现抽象方法A")
def B(self):
print("必须实现抽象方法B")
impl = Implement()
impl.A()
impl.B()
如果我们在实现类Implement中没有实现方法B,会提示如下:
但是我们全部实现后,就会很顺畅的输出结果如下:
利用Python的abc模块,我们可以将抽象机制应用在接口上,从而"实现接口"
回到本篇的内容,我们说下多继承
我们知道青蛙Frog,是两栖动物,既可以在陆地上跑,也可以在水里游,如果跑和游是两个更加抽象的类,需要被具体的话,那么仅凭单继承的话,青蛙只能继承一种父类行为,要么跑,要么游,假设,我们让青蛙先继承跑,然后,在这种跑的行为上,为青蛙"混入"额外的功能游,那么就必须让青蛙再继承游才行,这就必须要用到多继承了,这种设计模式在Python中称之为MixIn,中文我们就称"混入"吧。
针对上面描述的,我们设计我们的demo如下:
#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-
class Runnable():
def run(self):
print("I can run...")
class Swimable():
def swim(self):
print("I can swim...")
class Frog(Runnable,Swimable):
pass
print(Frog.__bases__)
我们利用类的属性__bases__打印出,当前类所继承的父类有哪些:
当然,如果我们的类,没有显示指明继承的父类,默认都是object:
我们看下值,不难发现,类的属性__bases__的值是一个tuple元组
其实,多继承很好理解,我们看下,青蛙王子,现在是不是既可以跑又可以游了:
so,多继承又扯了这么多,是时候该结束本篇的内容了,下一篇,我们再继续............