Python 多态与动态绑定
Python 多态基于鸭子类型,不依赖继承关系,只需对象具备所需方法。
鸭子类型
"如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子。"
Python
class Duck:
def swim(self):
print("鸭子游泳")
def quack(self):
print("嘎嘎")
class Person:
def swim(self):
print("人游泳")
def quack(self):
print("人模仿鸭子叫")
class Robot:
def swim(self):
print("机器人游泳")
def quack(self):
print("电子嘎嘎")
def make_it_quack(thing):
"不关心类型,只要有 quack 方法"
thing.quack()
def make_it_swim(thing):
"不关心类型,只要有 swim 方法"
thing.swim()
# 任何有这些方法的对象都可以使用
make_it_quack(Duck()) # 嘎嘎
make_it_quack(Person()) # 人模仿鸭子叫
make_it_quack(Robot()) # 电子嘎嘎
make_it_swim(Duck()) # 鸭子游泳
make_it_swim(Person()) # 人游泳
多态示例
Python
class File:
def read(self):
return "文件内容"
class Network:
def read(self):
return "网络数据"
class Database:
def read(self):
return "数据库记录"
def process_data(source):
"多态:任何有 read 方法的对象都适用"
data = source.read()
return f"处理: {data}"
print(process_data(File())) # 处理: 文件内容
print(process_data(Network())) # 处理: 网络数据
print(process_data(Database())) # 处理: 数据库记录
继承多态
Python
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "汪汪"
class Cat(Animal):
def speak(self):
return "喵喵"
class Cow(Animal):
def speak(self):
return "哞哞"
def animal_sound(animal: Animal):
"基于继承的多态"
print(animal.speak())
animals = [Dog(), Cat(), Cow()]
for animal in animals:
animal_sound(animal)
# 汪汪
# 喵喵
# 哞哞
动态绑定
方法在运行时绑定到对象:
Python
class A:
def method(self):
print("A 方法")
class B:
def method(self):
print("B 方法")
def call_method(obj):
obj.method() # 运行时动态绑定
call_method(A()) # A 方法
call_method(B()) # B 方法
# 同一变量可以是不同类型
obj = A()
obj.method() # A 方法
obj = B()
obj.method() # B 方法
方法动态添加
Python
class Dynamic:
pass
def new_method(self):
print("动态添加的方法")
d = Dynamic()
# 运行时添加方法
import types
d.method = types.MethodType(new_method, d)
d.method() # 动态添加的方法
# 添加到类
Dynamic.class_method = new_method
Dynamic().class_method() # 动态添加的方法
getattr 实现动态方法
Python
class DynamicProxy:
def __getattr__(self, name):
"动态创建方法"
def method(*args, **kwargs):
print(f"调用 {name},参数: {args}, {kwargs}")
return f"结果: {name}"
return method
proxy = DynamicProxy()
print(proxy.any_method(1, 2, key="value"))
# 调用 any_method,参数: (1, 2), {'key': 'value'}
# 结果: any_method
多态与类型检查
Python
# 鸭子类型:不检查类型
def process_duck(obj):
obj.quack() # 只要有 quack 方法
# 类型检查:检查是否是特定类型
def process_with_check(obj):
if hasattr(obj, 'quack'):
obj.quack()
else:
print("对象没有 quack 方法")
# 抽象基类:强制接口
from abc import ABC, abstractmethod
class Quacker(ABC):
@abstractmethod
def quack(self):
pass
def process_with_abc(obj: Quacker):
obj.quack() # 类型检查确保有 quack 方法
协议与抽象基类
Python
from collections.abc import Sized, Iterable
class MyCollection:
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data)
def __iter__(self):
return iter(self.data)
# 自动符合协议(鸭子类型)
mc = MyCollection([1, 2, 3])
print(isinstance(mc, Sized)) # True(有 __len__)
print(isinstance(mc, Iterable)) # True(有 __iter__)
# 无需显式继承
def get_size(obj: Sized):
return len(obj)
def iterate(obj: Iterable):
return list(obj)
print(get_size(mc)) # 3
print(iterate(mc)) # [1, 2, 3]
运算符多态
Python
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __str__(self):
return f"({self.x}, {self.y})"
p1 = Point(1, 2)
p2 = Point(3, 4)
print(p1 + p2) # (4, 6)(+ 运算符多态)
函数多态
内置函数对不同类型有不同行为:
Python
# len() 多态
print(len([1, 2, 3])) # 3(列表长度)
print(len("hello")) # 5(字符串长度)
print(len({"a": 1})) # 1(字典长度)
print(len(range(10))) # 10(range长度)
# str() 多态
print(str(123)) # 123(整数)
print(str([1, 2])) # [1, 2](列表)
print(str({"a": 1})) # {'a': 1}(字典)
# sorted() 多态
print(sorted([3, 1, 2])) # [1, 2, 3]
print(sorted("hello")) # ['e', 'h', 'l', 'l', 'o']
print(sorted({"a": 1, "b": 2})) # ['a', 'b'](按键排序)
接口协议示例
Python
class Reader:
"读取接口"
def read(self):
raise NotImplementedError
class Writer:
"写入接口"
def write(self, data):
raise NotImplementedError
class FileReader(Reader, Writer):
def __init__(self, filename):
self.filename = filename
def read(self):
with open(self.filename, 'r') as f:
return f.read()
def write(self, data):
with open(self.filename, 'w') as f:
f.write(data)
class NetworkReader(Reader):
def read(self):
return "网络数据"
class ConsoleWriter(Writer):
def write(self, data):
print(data)
# 多态使用
def copy_data(reader, writer):
data = reader.read()
writer.write(data)
copy_data(FileReader("source.txt"), ConsoleWriter())
copy_data(NetworkReader(), FileReader("dest.txt"))
鸭子类型 vs 显式接口
| 方式 | 特点 |
|---|---|
| 鸡子类型 | 无需继承,灵活,无编译检查 |
| 抽象基类 | 强制接口,有类型检查保障 |
| 类型注解 | 提供静态提示,不强制运行 |
Python
# 鸡子类型
def process(obj):
obj.method() # 运行时可能失败
# 抽象基类
def process(obj: Interface):
obj.method() # 确保有 method
动态属性绑定
Python
class Dynamic:
pass
d = Dynamic()
# 运行时添加属性
d.name = "动态"
d.value = 100
print(d.name) # 动态
print(d.value) # 100
# 动态删除属性
del d.value
# print(d.value) # AttributeError
要点总结
| 要点 | 说明 |
|---|---|
| 鸡子类型 | 只需具备方法,无需继承 |
| 多态 | 同一接口不同实现 |
| 动态绑定 | 运行时确定方法调用 |
| 协议 | 通过方法集合定义接口 |
| hasattr() | 检查对象是否有方法 |
Python 多态基于鸭子类型,灵活但无编译时检查;抽象基类提供接口约束保障。
D:\git2\jwdev\articles\PYTHON\进阶\面向对象编程\多态与动态绑定.md
📝 发现内容有误?点击此处直接编辑