Python的鸭子类型和多态
一、鸭子类型
当你看见一只鸟走起来像鸭子,游起泳来像鸭子,叫起来也像鸭子,那么这只鸟就可以被称为鸭子
class Cat(object):
def say(self):
print("i am a cat")
class Dog(object):
def say(self):
print("i am a dog")
class Duck(object):
def say(self):
print("i am a duck")
animal = Cat()
animal.say() # i am a cat
上面三个类中都包含了say
方法。
先实例化一个animal
对象,然后在运行时可能给它赋值成Cat
、Dog
或者Duck
,所以是不确定的。
在java
中实现多态,一般是这样做,先定义一个父类Animal
,其中包含一个say
方法,然后再定义继承Animal
类的Cat
子类,并在Cat
子类中重写say
方法,这样才能指明Cat
是Animal
的子类。
基于java
思想,用python
语言来实现多态概念
class Animal:
def say(self):
print("i am a animal")
class Cat(Animal):
def say(self):
print("i am a cat")
Animal an = Cat()
#在java中声明变量时需要定义变量类型,python中不能这样写
an.say() #调用子类方法
而在Python中实例化的对象是一个动态的变量,可以指向任何类型,指需要在类中把方法写出来即可。如下边得代码一样。
animal_list = [Cat,Dog,Duck]
for animal in animal_list:
animal().say()
# i am a cat
# i am a dog
# i am a duck
当各类实现了共同的方法名,就可以循环调用同一个方法,实现了多态,相比java
中需要继承一个父类再重写类的方法而言就简单多了。
也就是说当所有类或对象实现了共同的方法,这个方法名也一样,那这些类就可以归为一种类型。
二、下面再来看一个例子
a = ["bobby1", "bobby2"]
b = ["bobby2", "bobby"]
name_tuple = ["bobby3", "bobby4"]
name_set = set()
name_set.add("bobby5")
name_set.add("bobby6")
a.extend(b)
print(a) # ["bobby1", "bobby2","bobby2", "bobby"]
想一个问题,extend
函数只能穿进来一个列表吗?
在源码中extend
函数是这样定义的
def extend(self, iterable: Iterable[_T]) -> None: ...
所以说extend
函数不光可以用list作为参数,任何可以迭代的对象都是可以的,而在Python
中tuple
、set
都是可迭代的对象。
所以往extend
函数中传name_set
和name_tuple
都可以。
a = ["bobby1", "bobby2"]
name_tuple = ["bobby3", "bobby4"]
name_set = set()
name_set.add("bobby5")
name_set.add("bobby6")
# a.extend(name_tuple)
# print(a) # ["bobby1", "bobby2","bobby3", "bobby4"]
a.extend(name_set)
print(a) # ["bobby1", "bobby2","bobby5", "bobby6"]
三、往extend函数中传入可迭代的类
class Company(object):
def __init__(self, employee_list):
self.employee = employee_list
def __getitem__(self, item):
return self.employee[item]
def __len__(self):
return len(self.employee)
company = Company(["tom", "bob", "jane"])
a = ["bobby1", "bobby2"]
a.extend(company)
print(a) # ["bobby1", "bobby2","tom", "bob", "jane"]
extend
函数会隐含调用对象中的迭代器,比如__iter__
、__getitem__
之类的(调用之后就变成可迭代的对象了)。
小节
在python中魔法函数充分利用了鸭子类型,在对象中写入很多魔法函数,可以被python解释器本身识别,在很多python内置的对象或内置的类中都具有非常好用的特性,比如可迭代的特性,上下文管理器、集合序列相关特性等,代码本身更加灵活。