要想学习python,就得明白面向对象(oop)。众所周知,封装、继承、多态是面向对象的三大特征。作为一门高级语言,python本身具备的多优势无需多言,然而就其中的继承和多态特性,我们来了解一下鸭子类型。
维基百科中对鸭子类型是这样描述:在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。这个概念的名字来源于由James Whitcomb Riley提出的鸭子测试,“鸭子测试”可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
从上面的描述中我们得知:鸭子类型无非就是如果一种动物只要行为有相似性,那么我们就可以认为是鸭子。
鸭子: 我会游泳 ,我是鸭子 鹅:我会游泳,我也是鸭子。。。。
python是一门动态语言。动态语言与静态语言的最大区别便是动态语言是在运行时确定数据类型的语言(python,JavaScript),变量使用之前不需要类型声明。而静态语言便是在编译时变量的数据类型即可确定的语言(java,c++,C#)。
两者各有利弊。
鸭子类型在动态语言中经常使用,非常灵活,使得python不会像java那样专门去弄一大堆的设计模式。鸭子类型在python语言里有一个词叫做““file-like object“”,同时有很多file-like的东西,比如StringIO,GzipFile,Socket。它们有很多相同的方法,我们把它们当作文件使用。对真正的文件对象,它有一个read()
方法,返回其内容。但是,许多对象,只要有read()
方法,都被视为“file-like object“。许多函数接收的参数就是“file-like object“,你不一定要传入真正的文件对象,完全可以传入任何实现了read()
方法的对象。
现在用代码作简要说明:
class duck():
def walk(self):
print('I walk, i am a duck')
def swim(self):
print('i swim,i am a duck')
class geese():
def walk(self):
print('i walk like a duck')
def swim(self):
print('i swim like a duck')
下面再用一个发方法调用:
def watch_duck(a):
a.walk()
a.swim()
small_duck = duck()
watch_duck(small_duck)
output >>
I walk like a duck
i swim like a duck
duck_like_man = person()
watch_duck(duck_like_man)
output >>
this one walk like a duck
this man swim like a duck
从上面可以看出,只要有watch_duck
函数接收这个类的对象,然后并没有检查对象的类型,而是直接调用这个对象的walk和swim方法,如果所需要的方法不存在就报错。
从上面可以看出,python鸭子类型的灵活性在于它关注的是这个所调用的对象是如何被使用的,而没有关注对象类型的本身是什么。