Python中的多态是面向对象编程中的一个重要概念。多态性(Polymorphism)指的是能够使用统一的接口来操作不同类型的对象。在Python中,多态表现为不同类的对象对同一消息可以作出不同的响应。以下是多态的一些关键特征和示例:
关键特征
- 接口一致性:不同对象可以对相同的方法调用做出不同的响应。
- 松耦合:代码与对象类型之间的耦合性较低,增加了代码的灵活性和可扩展性。
- 替代性:一个类的对象可以在需要另一个类对象的地方替代使用。
简单说,多态指的是一类事物有多种形态,比如动物有多种形态:猫、狗、猪。另外,子类可以重写父类中的方法,使得即使通过父类的接口调用这些方法,也可以执行子类特有的行为。代码如下:
#第1章/lei.py
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.talk() # 喵喵喵
dog.talk() # 汪汪汪
pig.talk() # 哼哼哼
Python中一切皆对象,本身就支持多态性。多态性的好处在于增强了程序的灵活性和可扩展性.
最后,可以通过关键字@abc.abstractmethod在父类引入抽象类的概念来硬性限定子类必须有某些方法名,代码如下:
#第1章/lei.py
import abc
# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
def talk(self): # 抽象方法中无需实现具体的功能
pass
class Cat(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
pass
cat=Cat()
鸭子类型
实际上,多态的概念是应用Java和C#这一类强类型语言中,而Python崇尚的是 “鸭子类型(Duck Typing)”,鸭子类型是一个编程概念,源自一个古老的说法:“如果它走路像鸭子、叫声像鸭子,那么它就是鸭子。” 在编程中,这个概念被用来说明一个对象的适用性是由它的行为和属性决定的,而不是它的具体类别。
想象一下,你在设计一个游戏,需要一些能够“叫”的动物。在游戏中,只要某个动物能发出叫声,不管它实际上是什么动物,你都可以把它当作游戏中的角色。
比如,你有一个函数,它需要一个会发出叫声的动物。在鸭子类型的思维中,只要是能“叫”的东西都可以传给这个函数,不管它是不是真正的鸭子。它可能是一只狗,但只要它能以某种方式“叫”,这个函数就会接受它并让它“叫”。
#定义时的类型和运行时的类型不一样,就是多态的体现
#Python崇尚鸭子类型
class Cat(object):
def say(self):
print("i am Cat")
class Dog(object):
def say(self):
print("i am Dog")
class Duck(object):
def say(self):
print("i am Duck")
# 以上定义了三个类
animal_list = [Cat, Dog, Duck] # 这里将三个封装好的类分别作为animal_list的三个元素
for animal in animal_list: # animal_list是一个列表,是可迭代的对象
animal().say() # animal()是实例化对象的过程,然后分别调用 Cat, Dog, Duck的say方法
'''
i am Cat
i am Dog
i am Duck
'''
鸭子类型的好处
- 提高代码灵活性:因为不强制要求对象属于特定的类别,只要对象具有所需的行为(方法和属性),就可以在任何需要这些行为的场合使用它们。这使得代码更加灵活,可以接受各种不同类型的对象。
- 减少重复代码:在传统的继承模型中,如果多个类具有相似的行为,可能需要重复定义这些行为。而在鸭子类型中,只要对象实现了所需的方法,无论它的类继承结构如何,都可以使用这个对象,减少了代码重复。
- 避免复杂的继承结构:在一些编程场景中,为了实现特定的接口或行为,可能需要创建复杂的继承链。鸭子类型使得我们无需担心对象的具体类别,只关注它的行为,从而避免了复杂的继承结构。
鸭子类型的坏处
- 代码可读性和明确性降低:由于不强制要求对象的类型,代码可能难以理解,特别是对于大型代码库或团队项目,理解对象的预期行为可能更加困难。
- 运行时错误:在编译型语言中,类型错误往往在编译期被捕捉到。但在鸭子类型的环境中,如果传递了错误的对象,可能只有在运行时才会发现问题,这可能导致运行时错误。
- 维护难度:随着项目规模的扩大,如果使用了大量基于鸭子类型的设计,代码的维护可能变得更加困难。因为需要理解每个对象的实际行为,而不是仅仅依赖于它们的类型定义。
结论
鸭子类型提供了一种灵活性和动态性的编程方式,它适用于许多情况,特别是在需要多态性但又不想涉及复杂继承结构的场合。然而,使用鸭子类型也需要考虑到其可能带来的可读性降低和维护难度增加的问题。正确的做法是根据具体的项目和团队的需要,在灵活性和严格类型检查之间找到平衡点。
暂无评论内容