鸭子类型
本课属于 Coddy Python 学习旅程的“面向对象编程”单元。第 24 课,共 64 课。
鸭子类型关注对象能做什么,而不是它是什么。只要对象具有你需要的方法,你就可以使用它,无论它属于什么类。
下面是两个互不相关但具有相同方法的类:
class Duck:
def swim(self):
return "Duck swimming"
def quack(self):
return "Quack!"
class Person:
def swim(self):
return "Person swimming"
def quack(self):
return "Person imitating a duck: Quack!"注意,Duck 和 Person 并没有继承自同一个父类,但它们都有 swim() 和 quack() 方法。
创建一个适用于任何“像鸭子的”对象的函数:
def make_it_swim_and_quack(duck_like_object):
print(duck_like_object.swim())
print(duck_like_object.quack())这个函数不关心对象的类型,只关心对象是否有必需的方法。
对这两个类都使用该函数:
make_it_swim_and_quack(Duck())
make_it_swim_and_quack(Person())输出:
Duck swimming
Quack!
Person swimming
Person imitating a duck: Quack!再添加一个“像鸭子一样”的类:
class Robot:
def swim(self):
return "Robot swimming with propellers"
def quack(self):
return "Robot sound: BEEP BEEP!"
make_it_swim_and_quack(Robot())输出:
Robot swimming with propellers
Robot sound: BEEP BEEP!要点:鸭子类型无需继承即可实现多态。只要对象具有你需要的方法,就可以使用它。这让 Python 代码更加灵活,也遵循“请求宽恕比请求许可更容易”的原则。
挑战
中等在这个挑战中,你将实现一个系统,通过不同的类文件对象演示鸭子类型:
textfile.py:实现TextFile类,包含read()和write(data)方法database.py:实现Database类,并使用匹配的方法签名networkresource.py:实现NetworkResource类,并使用匹配的方法签名driver.py:实现测试用例,验证你的实现能否正常工作
每个文件都包含详细的 TODO 注释,指导你完成实现。
亲手试试
# TODO: 从 textfile.py 导入 TextFile 类
# TODO: 从 database.py 导入 Database 类
# TODO: 从 networkresource.py 导入 NetworkResource 类
def process_data(data_source, data):
# TODO: 调用 data_source 的 read() 方法并打印结果
# TODO: 调用 data_source 的 write(data) 方法并打印结果
pass
# 使用不同的数据源进行测试。不要修改这段测试代码
text_file = TextFile()
database = Database()
network = NetworkResource()
print("Processing text file:")
process_data(text_file, "Hello, world!")
print("\
Processing database:")
process_data(database, "User record")
print("\
Processing network resource:")
process_data(network, "GET request")这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Python 在线编译器