使用路由类时,如何让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)时触发迭代错误。
修复步骤
修正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) # 其余方法保持不变修正Model抽象类的属性定义
抽象property不需要额外参数,修改item_type的定义:class Model(ABC): # ... 其他方法不变 @property @abstractmethod def item_type(self): # 移除多余的name参数 ...可选:在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
相关产品推荐
相关产品推荐

