3.鸭子类型和多态

Python鸭子类型与多态特性探析
本文探讨了Python中的鸭子类型,强调其动态性和多态性。通过对比Java,展示Python如何无需继承即可实现类似功能。此外,详细介绍了`extend`方法的使用,说明了其对可迭代对象的兼容性。最后,通过实例展示了自定义类如何与内置方法无缝配合,进一步体现了Python鸭子类型的灵活性。

鸭子类型和多态

鸭子类型:python因为是动态解释型语言,所以不受类型约束。本来就有多态属性。
举例看下:
下面代码通过与Java代码比较,就可以看出python鸭子类型的额方便之处。

1)java因为类型声明,需要通过各类继承一个抽象类来实现,python鸭子类型不需要继承一个类就能实现。

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

class Dog():
    def say(self):
        print("i am a dog")

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

object_list = [Cat,Dog,Duck]
for item in object_list:
    item().say()
》》》》》》》》》》》》》》》》》》》》》》》》》》》》
i am a cat
i am a dog
i am a duck

2)extend方法可以在list后边追加一个可迭代对象。不用保持类型一致。
extend的说明文档里面,可以看到入参是一个迭代类型。

def extend(self, iterable): # real signature unknown; restored from __doc__
    """ L.extend(iterable) -> None -- extend list by appending elements from the iterable """
    pass
list1 = ['tom','jarry','hac']
list2 = ['tom1','jarry1','hac1']
name_tuple = ('王二','张三','李四')
name_set = set()
name_set.add('王麻子')
name_set.add('二狗子')

list1.append(list2)
print('append list2 --->',list1)
list1.extend(list2)
print('extend list2 --->',list1)
list1.extend(name_set)
print('extend name_set --->',list1)
list1.extend(name_tuple)
print('extend name_tuple --->',list1)

》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
append list2 ---> ['tom', 'jarry', 'hac', ['tom1', 'jarry1', 'hac1']]
extend list2 ---> ['tom', 'jarry', 'hac', ['tom1', 'jarry1', 'hac1'], 'tom1', 'jarry1', 'hac1']
extend name_set ---> ['tom', 'jarry', 'hac', ['tom1', 'jarry1', 'hac1'], 'tom1', 'jarry1', 'hac1', '王麻子', '二狗子']
extend name_tuple ---> ['tom', 'jarry', 'hac', ['tom1', 'jarry1', 'hac1'], 'tom1', 'jarry1', 'hac1', '王麻子', '二狗子', '王二', '张三', '李四']

3)我们试着自己实现一个可迭代的类来试下。

可以看到extend 只要入参是可迭代的就行


class Three_dogs():
    def __init__(self,dogs):
        self.dog = dogs
	
	#实现迭代
    def __getitem__(self, item):
        return self.dog[item]


list1 = ['tom','jarry','hac']
list1.extend(Three_dogs(['dog1','dog2','dog3']))
print(list1)

-------------------------------------------
['tom', 'jarry', 'hac', 'dog1', 'dog2', 'dog3']
<think> 首先,用户的问题是关于Python多态的两种实现方式:方法重写鸭子类型多态的核心是同一接口在不同对象上呈现不同行为。 从系统指令中,我需要: - 使用$...$格式表示行内数学表达式(但这里可能不涉及数学表达式)。 - 独立公式用$$...$$格式(同样可能不适用)。 - LaTeX语法正确(确保代码块正确显示)。 - 使用中文回答。 - 生成相关问题。 - 在回答末尾添加引用标识。 - 回答结构清晰,逐步解决问题。 用户提供了多个引用,我需要参考这些引用来构建回答: - 引用[1]:讨论了方法重写、动态绑定抽象基类。 - 引用[2]:强调了鸭子类型使多态不依赖于继承。 - 引用[3]:展示了通过继承方法重写的例子。 - 引用[4]:解释了鸭子类型,不继承但实现相同方法。 - 引用[5]:提供了鸭子类型的另一个例子。 关键概念: - **方法重写**:通过子类继承父类并重写方法来实现多态。 - **鸭子类型**:不依赖于继承,只要对象有相同的方法或属性,就可以视为多态。 回答结构: 1. **引言**:解释多态的概念重要性。 2. **方法重写实现多态**:使用继承方法重写的例子。 3. **鸭子类型实现多态**:使用鸭子类型的例子。 4. **对比**:简要对比两种方式。 5. **总结**:强调Python多态的灵活性。 6. **相关问题**:生成3个相关问题。 确保内容真实可靠:基于提供的引用构建例子,避免虚构。 生成相关问题: 1. 基于回答内容,创建相关问题,如优缺点、应用场景等。 - 例如:方法重写鸭子类型在性能上的差异? - 或者:在实际项目中如何选择使用继承还是鸭子类型? - 确保相关问题相关且有价值。 引用标识:在回答中引用段落末尾添加[^1], [^2]等,对应到提供的引用列表。 最终输出: - 以中文回答。 - 包括代码块来演示例子。 - 结尾添加相关问题。 </think> ### Python中通过方法重写鸭子类型实现多态的方法 多态是面向对象编程的核心特性,指同一接口在不同对象上呈现不同行为。在Python中,多态可以通过两种主要方式实现:**方法重写(基于继承)** **鸭子类型(基于接口一致性)**。下面我将逐步解释这两种方法,并提供具体示例,确保内容基于可靠引用。 --- ### 1. **方法重写实现多态** 方法重写是通过继承机制实现的:子类继承父类并重写其方法,使同一方法在不同子类中表现不同行为。Python通过动态绑定在运行时确定调用的方法[^3]。 #### 示例代码 以下是一个基于继承方法重写的例子。假设有一个父类`Animal`,定义了`speak()`方法。不同子类重写该方法以提供特定实现: ```python class Animal: def speak(self): print("动物发音") # 父类的默认实现 class Dog(Animal): def speak(self): # 重写父类方法 print("汪汪汪...") # 狗的特定行为 class Cat(Animal): def speak(self): # 重写父类方法 print("喵喵喵...") # 猫的特定行为 class Hen(Animal): def speak(self): # 重写父类方法 print("咯咯咯...") # 鸡的特定行为 # 定义一个函数,接受Animal类型的对象 def make_sound(animal_obj): animal_obj.speak() # 同一接口调用speak方法 # 创建不同子类的对象 dog = Dog() cat = Cat() hen = Hen() # 调用函数,呈现多态行为 make_sound(dog) # 输出: 汪汪汪... make_sound(cat) # 输出: 喵喵喵... make_sound(hen) # 输出: 咯咯咯... ``` - **关键点**: - 所有子类继承自`Animal`父类,共享相同的接口`speak()`。 - 运行时动态绑定确保调用正确的子类方法(如`Dog.speak()`或`Cat.speak()`)。 - 这使代码灵活且可扩展,例如添加新动物子类时无需修改`make_sound`函数[^3]。 - 优点:结构清晰,适合需要严格类型层次的项目[^1]。 --- ### 2. **鸭子类型实现多态** 鸭子类型不依赖于继承,而是基于对象的接口一致性:如果一个对象有相同的方法或属性,它就可以被视为多态的,无论其类是否相关。Python的动态类型系统天然支持这种方式[^2][^4]。 #### 示例代码 以下是一个鸭子类型的例子。对象不需要继承自共同父类,只要实现相同方法(如`msg()`),就能被视为多态: ```python class Person: def msg(self): # 定义通用接口 print("人需要工作") class Animal: def msg(self): # 不继承Person,但实现相同方法 print("动物不需要工作") # 不同行为 class Bicycle: def msg(self): # 另一个独立类,实现相同方法 print("自行车不需要工作") # 独特行为 # 定义一个函数,接受任何有msg()方法的对象 def show_message(obj): obj.msg() # 同一接口调用msg方法 # 创建不同类的对象 person = Person() cat = Animal() bike = Bicycle() # 调用函数,呈现多态行为 show_message(person) # 输出: 人需要工作 show_message(cat) # 输出: 动物不需要工作 show_message(bike) # 输出: 自行车不需要工作 ``` - **关键点**: - 对象如`Animal``Bicycle`未继承`Person`,但都实现了`msg()`方法,符合接口要求。 - Python在运行时检查对象是否"看起来像鸭子"(即拥有所需方法),而不关心其类型[^4]。 - 优点:代码更简洁灵活,无需构建复杂的继承链,适合快速开发松耦合设计[^2][^5]。 - 典型应用:如支付系统中,不同支付方式(信用卡、PayPal)实现相同`pay()`方法[^1]。 --- ### 3. **两种方法的对比** - **方法重写**:依赖于继承,提供强类型安全结构,但可能引入冗余的类层次。 - **鸭子类型**:基于接口一致性,更灵活Pythonic,但可能牺牲类型检查的安全性。 - Python多态通常更倾向于鸭子类型,因为它符合语言的动态特性[^2][^5]。 --- ### 总结 在Python中,多态通过方法重写(继承驱动)鸭子类型(接口驱动)实现同一接口在不同对象上的多样性。方法重写适合需要严格控制的场景,而鸭子类型提供更高的灵活性简洁性。实际开发中,两者常结合使用,例如通过抽象基类定义接口,再通过鸭子类型实现具体对象[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值