当前位置:首页>python>Python 面向对象习题(习题8/10)

Python 面向对象习题(习题8/10)

  • 2026-09-02 15:45:43
Python 面向对象习题(习题8/10)

本文首发于微信公众号「拙见python」,基础板块第11 篇。
适合人群:已阅读第 2 篇:Python 面向对象编程并动手敲过代码的读者。
题目难度:⭐ → ⭐⭐⭐⭐⭐ 逐步提升,建议先自己写,再看答案。


做题须知

  • 每道题标注了考察知识点和难度星级
  • 先自己写,写不出来再看答案
  • 答案不是唯一的,能跑通且逻辑正确就行
  • 每道题答案下方附有思路解析

第 8 题:Mixin 组合与鸭子类型 ⭐⭐⭐⭐

考察知识点:Mixin 模式、多继承组合、鸭子类型、iter / len

使用 Mixin 模式构建一个灵活的数据容器:

  1. 定义 IterableMixin:实现 __iter__ 和 __len__,让容器可迭代、可 len()
  2. 定义 FilterableMixin:提供 filter(predicate) 方法返回满足条件的元素列表
  3. 定义 SerializableMixin:提供 to_json() 和 from_json() 方法
  4. 定义 DataContainer 类,组合以上三个 Mixin,内部用列表存储数据
  5. 再定义一个不继承任何类的 FakeContainer,只实现 __iter__ 和 __len__
  6. 写一个函数 process(container),利用鸭子类型处理任何「可迭代且有长度」的对象

参考答案:

import json# ========== Mixin 定义 ==========class IterableMixin:    ”””让容器可迭代、可求长度”””    def __iter__(self):        return iter(self._data)    def __len__(self):        return len(self._data)    def __getitem__(self, index):        return self._data[index]class FilterableMixin:    ”””提供过滤功能”””    def filter(self, predicate):        ”””返回满足条件的元素列表”””        return [item for item in self._data if predicate(item)]    def first(self, predicate=None):        ”””返回第一个满足条件的元素,无则 None”””        for item in self._data:            if predicate is None or predicate(item):                return item        return Noneclass SerializableMixin:    ”””提供 JSON 序列化功能”””    def to_json(self):        return json.dumps(self._data, ensure_ascii=False, default=str)    @classmethod    def from_json(cls, json_str):        data = json.loads(json_str)        return cls(data)# ========== 组合 Mixin 的数据容器 ==========class DataContainer(IterableMixin, FilterableMixin, SerializableMixin):    def __init__(self, data=None):        self._data = list(data) if data else []    def add(self, item):        self._data.append(item)        return self# 链式调用    def __repr__(self):        return f”DataContainer({self._data})”# ========== 鸭子类型:不继承任何东西 ==========class FakeContainer:    ”””不继承任何 Mixin,但实现了 __iter__ 和 __len__”””    def __init__(self, data):        self._items = data    def __iter__(self):        return iter(self._items)    def __len__(self):        return len(self._items)# ========== 鸭子类型函数 ==========def process(container):    ”””处理任何「可迭代且有长度」的对象——不看出身,看能力”””    print(f”  类型:{container.__class__.__name__}”)    print(f”  长度:{len(container)}”)    print(f”  内容:{list(container)}”)    print()# ========== 测试 ==========# DataContainer:拥有所有 Mixin 能力dc = DataContainer([1, 2, 3, 4, 5, 6, 7, 8])dc.add(9).add(10)# 链式调用print(”=== DataContainer 测试 ===”)print(f”repr: {dc}”)print(f”长度: {len(dc)}”)print(f”索引 [3]: {dc[3]}”)print(f”迭代: {[x for x in dc]}”)print(f”过滤偶数: {dc.filter(lambda x: x % 2 == 0)}”)print(f”第一个 >5: {dc.first(lambda x: x > 5)}”)# 序列化json_str = dc.to_json()print(f”to_json: {json_str}”)dc2 = DataContainer.from_json(json_str)print(f”from_json: {dc2}”)print()# FakeContainer:没有继承任何 Mixinprint(”=== 鸭子类型测试 ===”)fake = FakeContainer([”a”, ”b”, ”c”])print(”处理 DataContainer:”)process(dc)print(”处理 FakeContainer:”)process(fake)print(”处理普通列表:”)process([10, 20, 30])

输出结果:

=== DataContainer 测试 ===repr: DataContainer([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])长度: 10索引 [3]: 4迭代: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]过滤偶数: [2, 4, 6, 8, 10]第一个 >5: 6to_json: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]from_json: DataContainer([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])=== 鸭子类型测试 ===处理 DataContainer:  类型:DataContainer  长度:10  内容:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]处理 FakeContainer:  类型:FakeContainer  长度:3  内容:['a', 'b', 'c']处理普通列表:  类型:list  长度:3  内容:[10, 20, 30]

思路解析:

  • Mixin 设计原则:每个 Mixin 只提供一个维度的功能(可迭代、可过滤、可序列化),不单独使用,通过多继承组合到目标类中。DataContainer(IterableMixin, FilterableMixin, SerializableMixin) 一次性获得三种能力。

  • 所有 Mixin 都通过 self._data 访问数据——这是 Mixin 与目标类之间的隐式契约:目标类必须提供 _data 属性。

  • add() 返回 self 实现链式调用:dc.add(9).add(10)。

  • 鸭子类型:process() 函数不检查参数类型,只要对象实现了 __iter__() 和 __len__() 就能处理。FakeContainer、DataContainer、甚至普通 list 都能传入——"不看出身,看能力"。

建议的练习方式:

  1. 先自己写——不看答案,能写多少写多少
  2. 卡住了回看文章——第 2 篇对应章节有完整示例

关注「拙见python」,一起写干净的代码。


下一篇预告:Python 面向对象习题之9/10

最新文章

随机文章