【发布时间】:2020-01-03 16:56:59
【问题描述】:
我的设计
文字描述
我有一个班级Model,当然上面有一些方法。除此之外,我还有一个类ModelList,其子类表示Model 的q 个子类的实例列表。除此之外,ModelList 子类的使用是为了提供批量操作,这与仅将操作委托给ModelList 的每个元素不同。因此,ModelList 子类的目的是“矢量化”相应Model 类的方法。
我还在某些地方使用ModelList,我希望允许Model 或ModelList 的子类作为参数传递给函数。
ModelList 知道(并检查)其任何元素将接受的类型。为了让ModelList 子类知道其对应的Model 子类,我将其定义为ModelList 子类上的类变量element_type。
每个ModelList 子类都与Model 子类紧密耦合:一个ModelList 类属于一个Model 类。这就是为什么我将ModelList 子类作为内部类放到它们各自的Model 类中。我的问题来了:因为ModelList 需要知道Model 和Model 需要知道ModelList 并且在每个类的初始化过程中,我的类之间都有循环依赖关系。
最小示例
为了让我的设计更易于理解,我将代码缩减为最小示例:
class Model(ABC):
pass
class ModelList(list):
@classmethod
def __init__(self, elements=None):
elements = list() if not elements else elements
for value in elements:
self._check_type(value)
list.__init__(self, elements)
def _check_type(self, val):
if not isinstance(val, self.__class__.element_type):
raise TypeError(
f"{self.__class__} accepts only instances of {self.__class__.element_type} as elements. `{val}` is not!")
以下导致错误free variable 'SomeModel' referenced before assignment in enclosing scope:
class SomeModel(Model):
class List(ModelList):
element_type = SomeModel # this causes the Error
我不想解耦
我知道我可以通过解耦这两个类来摆脱循环依赖。但我确实想要Model 类知道其对应的ModelList 类,并且我希望ModelList 类知道它的Model 类。每个Model 类都应该有一个且只有一个List 附加到它上面。
猴子补丁合适吗?
我知道我可以像这样通过“monkeypatching”我的Model 子类来规避依赖:
class SomeModel(Model):
pass
class SomeModelList(ModelList):
element_type = SomeModel
SomeModel.List = SomeModelList
对我来说,这感觉像是设计缺陷的标志。我不能说为什么,但感觉“不对”。
问题
- 猴子补丁在这里合适吗?或者它是否表明我的设计存在更深层次的概念问题?
- 还有哪些其他解决方案?
- 如何重新设计以摆脱这种循环依赖(但仍保持类的耦合)?
- 是否可以在稍后定义相应的
Model子类时评估element_type?
【问题讨论】:
-
您似乎想要创建一个类型安全的列表,但请注意,您仍然可以通过使用 append、insert、+ 或 += 将另一种类型的对象添加到列表类中。
-
@sloth 谢谢,我知道这一点,我已经添加了所有神奇的方法来确保这些列表操作将生成
ModelList子类的实例。为了创建一个最小的示例,我只是在这里没有提及它们。我想,我也应该放弃list的继承来创造一个真正的ME。 -
是的,所有这些问题都在告诉您设计存在缺陷,但您事先已经知道,并且您说您希望它有缺陷。如果这种设计被认为有缺陷的原因对你来说并不重要,或者它给你带来了比潜在问题更有价值的东西,那就继续吧。
标签: python oop design-patterns monkeypatching decoupling