“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
上面的这句话,不要去把鸭子理解为我们日常生活中见到的那种真正的鸭子,而是应该把它理解为一个类型(类型,而不是类),我们平时说的鸭子当然本身就属于鸭子类型了,但是如果现在还有一类鸟(类,而不是类型)也看起来像鸭子,游泳像鸭子,叫起来叫鸭子,虽然不是真正的鸭子,我们也把它归类到鸭子这个类型里面。
而鸭子类型是Python语言的一个特征。下面通过代码来理解Python的这一特征。
class Animal(object):
def run(self):
print("The animal is running...")
class Dog(Animal):
def run(self):
print('The dog is running...')
class Cat(Animal):
def run(self):
print('The cat is running...')
def makeRun(animalType):
animalType.run()
dog = Dog()
cat = Cat()
makeRun(dog)
makeRun(cat)
输出结果为:
The dog is running...
The cat is running...
使用一个函数 makeRun() 来访问不同 Animal 子类中的相同方法。但其实对于上面的 makeRun() 函数来说,传入的参数并不一定需要是 Animal 类型的,只需要保证传入的对象有一个 run() 方法即可,如下面代码所示。这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。如果run() 的方法不存在,那么将引发一个运行时错误。
class Person(object):
def run(self):
print("The person is running...")
person = Person()
makeRun(person)
----------------------------
The person is running...
而在静态语言中,如 Java ,如果需要传入 Animal 类型,则传入的对象就必须是 Animal 类型或者它的子类,否则,将无法调用 run() 方法。
由此可知,只要这些类都实现一样的方法,都可以归为一类型。
python的鸭子类型的设计让python的诸多对象的分类和应用更加灵活,需要注意类型和对象的区别(python的类也是对象),类型概念包含的范围更广,比如可迭代类型就包括list,tuple等类,这里list和tuple是类的概念,可迭代类型是类型的概念,可以看到可迭代类型包含了list和tuple这两个类,所以说类型的概念大于类的概念,当然一个类可以是属于多个类型的,比如list既属于可迭代类型,又属于序列类型。
python内置了一些类型,比如上面说的可迭代类型,还有数值类型(int,float,bool等),序列类型(list,str,tuple等),上下文管理类型(可以使用with语句的类型)等等。
一个对象实现了__getitem__魔法方法,那python解释器就会把它当做一个callection,你就可以对这个对象进行切片、获取子项等; 如果一个对象实现了__iter__和next方法,python就会把它当成一个iterator, 你就可以对这个对象通过循环获取各个子项; 如果一个对象中实现了__len__方法,你就可以对这个对象执行len()对它进行计数。
再举一个例子,比如python的列表有个方法叫extend,先看下这个函数的定义:
作用是在一个列表后面拼接另一个可迭代类型的对象,比如:
list_a = [1, 2, 3]
list_b = [4, 5]
set_c = (6, 7)
list_a.extend(list_b)
list_a.extend(set_c)
print(list_a)输出结果:[1, 2, 3, 4, 5, 6, 7]
可以看到list_b是一个列表,set_c是一个集合,他们都是可迭代类型,都可以通过list_a的extend方法拼接到list_a后面,这样就体现了python的灵活性了,因为按我们一般的思路,一个列表后面只能是拼接一个列表才对,可是这里却不这么限定,只要是个可迭代类型就都可以拼接,极大丰富了应用的范围。这就体现了鸭子类型的优势了,list和set都是可迭代类型(即都看起来像鸭子),只要是可迭代我就给你可拼接到一个列表的功能(只要是鸭子类型就可以做某件事)
结语
鸭子类型是动态语言中的一种设计风格,一个对象的特征不是由父类决定,而是通过对象的方法决定的。
Python 不是不支持多态,而是 Python 本身就是一门多态的语言,崇尚鸭子类型。