多态与鸭子类型

发布时间 2023-03-26 16:13:03作者: 星空看海

多态与多态性

多态指的是一类事物有多种形态,比如动物有多种形态:猫、狗、猪

多态

class Animal: # 同一类事物:动物
    def talk(self):  # 父类里面的方法不在实现具体的功能,只是定义继承父类的子类中一定要有这个方法
        pass
class Cat(Animal): # 动物的形态之一:猫
    def talk(self): 
        print('喵喵喵')
class Dog(Animal): # 动物的形态之二:狗
    def talk(self):
        print('汪汪汪')
class Pig(Animal): # 动物的形态之三:猪
    def talk(self):
        print('哼哼哼')

# 实例化得到三个对象
cat=Cat()
dog=Dog()
pig=Pig()

多态性指的是可以在不用考虑对象具体类型的情况下而直接使用对象,这就需要在设计时,把对象的使用方法统一成一种:例如cat、dog、pig都是动物,但凡是动物肯定有talk方法,于是我们可以不用考虑它们三者的具体是什么类型的动物,而直接使用

cat.talk()
# >>> 喵喵喵
dog.talk()
# >>> 汪汪汪
pig.talk()
# >>> 哼哼哼

更进一步,我们可以定义一个统一的接口来使用

def Talk(animal):
    animal.talk()

Talk(cat)
# >>> 喵喵喵
Talk(dog)
# >>> 汪汪汪
Talk(pig)
# >>> 哼哼哼

多态性的好处在于增强了程序的灵活性和可扩展性,比如通过继承Animal类创建了一个新的类,实例化得到的对象obj,可以使用相同的方式使用obj.talk()

class Wolf(Animal): #动物的另外一种形态:狼
    def talk(self):
        print('嗷...')

wolf=Wolf() # 实例出一头狼
wolf.talk() # 使用者根本无需关心wolf是什么类型而调用talk
# >>> 嗷...

抽象类

综上我们得知,多态性的本质在于不同的类中定义有相同的方法名,这样我们就可以不考虑类而统一用一种方式去使用对象,可以通过在父类引入抽象类的概念来硬性限制子类必须有某些方法名

'''
	需要掌握:
	1.如何限制抽象类
	2.抽象类的特点:只能被继承了,不能被实例化(面试题)
	3.抽象类可以限制子类里面必须要有父类定义的方法,
'''
import abc  # abstract class  抽象类

'''抽象类的特点:只能被继承了,不能被实例化'''
class Animal(metaclass=abc.ABCMeta):  # 这个类就变成了抽象类
    @abc.abstractmethod
    def speak(self):  # 类里面的方法就变成了抽象方法
        pass  

# Animal()  抽象类实例化会报错
# Can't instantiate(实例化) abstract class Animal with abstract with abstract methods speak

class Pig(Animal):
    def speak(self):
        pass


class Dog(Animal):
    def speak(self):
        pass

'''抽象类的这种写法,python不建议写'''

python中的多态实例

len('abcdefg')
len([1,2,3,4])
len({'username':1})

'''多态带来的特性:在不考虑对象具体的类型下,直接调用对应的方法或者属性'''
def len(obj):
    return obj.__len__()  # obj.__len__() ==>len(obj)

res=len('abcd')  # 4
res=len([1,2,3,4,5,6])  # 6
res=len({'a':1})  # 1
res=len(1)  # 求整型会报错
print(res)

len就是一种多态,无论你传过来是什么类型,都直接调用方法,不强制,能求就输出结果,不能就报错

鸭子类型

Python术语表中的鸭子类型 duck-typing:

译文:
鸭子类型是一种编程风格,决定一个对象是否有正确的接口,关注点在于它的方法或属性,而不是它的类型(“如果它看起来像鸭子,像鸭子一样嘎嘎叫,那么它一定是鸭子。”)。通过强调接口而不是特定类型,设计良好的代码通过多态提高了灵活性。鸭子类型无需使用 type() 或 isinstance() 进行检查(注意,鸭子类型可以用抽象基类来补充),相反,它通常使用 hasattr() 来检查,或是 EAFP 编程。

但其实我们完全可以不依赖于继承,只需要制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象,这正是Python崇尚的“鸭子类型”(duck typing):“如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子”。比起继承的方式,鸭子类型在某种程度上实现了程序的松耦合度,如下

我们并不关心对象是什么类型,到底是不是鸭子,只关心行为(即功能)

class People():
    def speak(self):
        print('People.speak')


class Pig():
    def speak(self):
        print('Pig.speak')


class Dog():
    def speak(self):
        print('Dog.speak')

obj = People()
obj1 = Pig()
obj2 = Dog()

obj.speak()  # 默认认为你有,但是你不一定有
obj.speak()  # 没有就会报错
obj2.speak()


# python中好多地方用鸭子类型
def animal(obj):  # 定义一个方法,把对象当成参数传递进去
    return obj.speak()
# 调用:
animal(obj)  # 认为你是动物,就认为你有speak功能,
animal(obj1)  # 有就输出,没有就报错
animal(obj2)

不加父类来限制,约定俗成的每个类(即上面的子类)中都定义一个同样的方法(animal的功能)

只要有animal的speak就认为是animal类

我们并不关心对象是什么类型,到底是不是鸭子,只关心行为(即功能)