You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用路由类时,如何让ABC子类的__iter__生效以保持模型可迭代?

问题:使用路由类后模型出现TypeError: 'ABCMeta' object is not iterable错误

我正在开发一个带路由功能的MVC框架,模型本身具备可迭代性。不使用路由类时,模型可正常返回所有首个键值;但使用路由类后,出现错误:TypeError: 'ABCMeta' object is not iterable。

简化源码

Model

from abc import ABC, abstractmethod

class Model(ABC):
    @abstractmethod
    def __iter__(self):
        ...

    @abstractmethod
    def get(self, item):
        ...

    @property
    @abstractmethod
    def item_type(self, name):
        ...


class TestModel(Model):
    test_items = {
        "one": { "name": "1" },
        "two": { "name": "2" },
    }

    item_type = "test"

    def __iter__(self):
        yield from self.test_items
        

    def get(self, item):
        try:
            return self.test_items[item]
        except KeyError as key_err:
            print("Key cannot be found", key_err)

Controller

from abc import ABC, abstractmethod

class Controller(ABC):
    @abstractmethod
    def __iter__(self):
        ...

    @abstractmethod
    def show_items(self):
        ...

    @abstractmethod
    def show_item_information(self, item_name):
        ...

class TestController:
    def __init__(self, model, view):
        self.view = view
        self.model = model

    def show_items(self):
        items = list(self.model)
        item_type = self.model.item_type
        self.view.show_item_list(item_type, items)

    def show_item_information(self, item_name):
        try:
            item_info = self.model.get(item_name)
        except Exception:
            item_type = self.model.item_type
            self.view.item_not_found(item_type, item_name)
        else:
            item_type = self.model.item_type
            self.view.show_item_information(item_type, item_name, item_info)

Router

class Router:
    def __init__(self):
        self.routes = {}

    def register_controller(self, path, controller, model, view):
        self.routes[path] = controller(model, view)

    def resolve(self, path):
        callback = self.routes.get(path)
        if callback:
            return callback
        return self.default_controller

    def default_controller(self, *args, **kwargs):
        status = 'Controller not found'
        return status

Main

#!/usr/bin/env python3

from sys import argv

from lib.router import Router
from lib.model import TestModel
from lib.view import TestView
from lib.controller import TestController

def main():
    router = Router()
    router.register_controller('test', TestController, TestModel, TestView)

    path = argv[1]

    controller = router.resolve(path)
    controller.show_items()


if __name__ == '__main__':
    main()

我期望通过路由后模型仍保持可迭代性,曾尝试添加可迭代性检查,但这并非有效解决方案。


问题分析与修复方案

错误根源

在Router的register_controller方法中,你直接将TestModel类传入了controller(model, view),而非TestModel的实例。控制器初始化时拿到的是Model类本身(ABCMeta类型),而非可迭代的实例,因此调用list(self.model)时触发迭代错误。

修复步骤

  1. 修正Router的注册逻辑
    注册时需要实例化模型和视图,而非直接传入类:

    class Router:
        def __init__(self):
            self.routes = {}
    
        def register_controller(self, path, controller, model_cls, view_cls):
            # 实例化模型和视图
            model = model_cls()
            view = view_cls()
            self.routes[path] = controller(model, view)
    
        # 其余方法保持不变
    
  2. 修正Model抽象类的属性定义
    抽象property不需要额外参数,修改item_type的定义:

    class Model(ABC):
        # ... 其他方法不变
        @property
        @abstractmethod
        def item_type(self):  # 移除多余的name参数
            ...
    
  3. 可选:在Main中直接传入实例
    若不想修改Router,也可以在注册时提前实例化模型和视图:

    def main():
        router = Router()
        test_model = TestModel()
        test_view = TestView()
        router.register_controller('test', TestController, test_model, test_view)
    
        path = argv[1]
        controller = router.resolve(path)
        controller.show_items()
    

完成以上修改后,控制器将拿到可迭代的TestModel实例,即可正常执行迭代操作。

内容的提问来源于stack exchange,提问作者Typnix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 21:08:09