Python Academy · 课时

多态与鸭子类型

编写适用于任何兼容对象的多态代码。

第 4 / 4 课14 个步骤

多态与鸭子类型 是 CoddyKit 上的免费 Python Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Python Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Python Academy 课程共包含 4 节课。

简介

多态允许不同对象响应同一个接口。鸭子类型的含义是:如果一个对象的行为像鸭子,那么它就是鸭子。

什么是多态

多态意味着“多种形式”。同一个方法名可以在不同对象上表现出不同的行为。Python 对此进行了广泛应用。
class Cat:
    def speak(self): return 'Meow'
class Dog:
    def speak(self): return 'Woof'
for animal in [Cat(), Dog()]:
    print(animal.speak())

鸭子类型

Python 不要求多态必须依赖类层次结构。只要对象拥有正确的方法,就可以正常工作。无需使用接口。
class Duck:
    def quack(self): return 'Quack'
class Person:
    def quack(self): return 'I am quacking like a duck'
def make_it_quack(duck):
    print(duck.quack())
make_it_quack(Duck())
make_it_quack(Person())

多态函数

len() 可以用于字符串、列表、字典和元组——这是因为它们都实现了 __len__。这就是内置多态。
for obj in ['hello', [1,2,3], {'a':1}]:
    print(type(obj).__name__, len(obj))

运算符重载

+ 可以用于整数、浮点数、字符串和列表,因为每种类型都以不同方式实现了 __add__。
print(1 + 2)        # int addition
print('a' + 'b')    # string concat
print([1] + [2])    # list concat

基于协议的鸭子类型

迭代协议规定:任何拥有 __iter__ 和 __next__ 的对象都可以用于 for 循环——无需继承基类。
class Squares:
    def __init__(self, n): self.n,self.i=n,0
    def __iter__(self): return self
    def __next__(self):
        if self.i>=self.n: raise StopIteration
        x=self.i**2; self.i+=1; return x
print(list(Squares(5)))

EAFP 与 LBYL

EAFP(请求宽恕比请求许可更容易)使用 try/except。LBYL(先观察再行动)使用 if/hasattr。Python 更倾向于 EAFP。
# LBYL:
if hasattr(obj, 'quack'):
    obj.quack()
# EAFP (Pythonic):
try:
    'hello'.quack()
except AttributeError:
    print('no quack')

使用 isinstance() 安全分派

当您需要针对不同类型执行特定行为时,使用 isinstance() 比捕获 AttributeError 更清晰。
def process(data):
    if isinstance(data, str):
        return data.upper()
    elif isinstance(data, list):
        return [x*2 for x in data]
print(process('hi'))
print(process([1,2,3]))

将抽象基类用作协议

from abc import ABC, abstractmethod 定义了正式协议。子类必须实现抽象方法。
from abc import ABC, abstractmethod
class Drawable(ABC):
    @abstractmethod
    def draw(self): pass
class Circle(Drawable):
    def draw(self): print('O')
Circle().draw()

typing.Protocol(3.8+)

class MyProtocol(Protocol): 无需使用 ABC 即可定义结构化子类型。它可以与 mypy 一起进行静态检查。
from typing import Protocol
class Quackable(Protocol):
    def quack(self) -> str: ...
def make_quack(x: Quackable) -> str:
    return x.quack()
print('protocol demo')

实际应用中的多态

请设计能够接受任何具有正确接口的对象的 API。这样无需修改代码即可扩展其功能。
class JSONSerializer:
    def serialize(self, obj): import json; return json.dumps(obj)
class XMLSerializer:
    def serialize(self, obj): return f'<data>{obj}</data>'
def export(data, serializer):
    return serializer.serialize(data)
print(export({'x': 1}, JSONSerializer()))

快速检查

在 Python 中,鸭子类型是什么意思?

回顾

多态:相同接口,不同行为。鸭子类型:关注行为,而不是类型。协议以非正式方式定义接口。EAFP(try/except)符合 Python 风格。

继续学习

进步非常出色!请继续学习,掌握下一个概念。
免费开始

用 AI 导师学习 Python — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
76
课程
320

常见问题解答

「多态与鸭子类型」课时是免费的吗?

是的 — 「多态与鸭子类型」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Python Academy 课程的其余内容,请升级到 CoddyKit PRO。 Python Academy 课程共包含 4 节课。

「多态与鸭子类型」这节课中我会学到什么?

编写适用于任何兼容对象的多态代码。 你通过在浏览器中直接运行的动手代码来练习 Python Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Python Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Python Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「多态与鸭子类型」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Python Academy 课中编写并运行代码吗?

能。每节 Python Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 单继承
  2. 方法重写与 super()
  3. 多重继承与 MRO
  4. 多态与鸭子类型
← 返回 Python Academy