这个概念的名字来源于James Whitcomb Riley提出的鸭子测试:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”

我们先来看一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Dog(object):
def say(self):
print("I am a dog")


class Cat(object):
def say(self):
print("I am a cat")


class Duck(object):
def say(self):
print("I am a duck")


animal_list = [Dog, Cat, Duck]
for animal in animal_list:
animal().say()

# 输出结果:

I am a dog
I am a cat
I am a duck

在上面的例子里面,3个类彼此之间没有任何的继承关系(除object类以外所有的类都继承object这个类),但是它们都有一个say方法,也正是由于这个say方法的存在,使得它们可以同时被作为一个”类”进行访问,这就是鸭子类型。鸭子类(duck typing):是动态类型的一种风格,不是由继承特定的类或实现特定的接口,而是当前的方法和属性的集合决定,鸭子类型中关注的不是对象的类型本身,而是它如何使用。也就是说在刚才的例子里面,我们并没有关注你是谁的实例化对象:Dog,Cat,Duck,只要你们都具有say方法就够了。

我们再来看另外一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
a_list = ["envse1", "envse2"]
b =["envse"]

a_tuple = ("envse3", "envse4")

a_set =set()
a_set.add("envse5")
a_set.add("envse6")

print("************************************")
a_list.extend(a_tuple)
print(a_list)


print("************************************")
a_list.extend(a_set)
print(a_list)


# 输出结果:

************************************
['envse1', 'envse2', 'envse3', 'envse4']
************************************
['envse1', 'envse2', 'envse3', 'envse4', 'envse5', 'envse6']

我们在这里调用了list的extend方法,我们通过源码(按住Ctrl+鼠标左键)发现里面只要传入的参数是iterable就可以进行添加:

1
2
3
def extend(self, iterable): # real signature unknown; restored from __doc__
""" L.extend(iterable) -> None -- extend list by appending elements from the iterable """
pass

所以就加深了我们对鸭子类型的印象。

现在说一下多态,在Java里面,实现多态的前提是具有继承关系,但在Python里面就不是了,python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型,有鸭子类型这就够了。

[ - ] 参考文章:谈谈Python的鸭子类型python鸭子类型