Class 架构:内部和外部的循环依赖 Class in Python
Class Architecture: Circular Dependency of Inner and Outer Class in Python
我的设计
口头描述
我有一个classModel
,当然上面有一些方法。除此之外,我还有一个 class ModelList
,其 childclass 表示 Model
的 q child class 的实例列表。除其他外,ModelList
child classes 的使用是提供批量操作,这不同于仅将操作委托给 ModelList
的每个元素。因此,ModelList
child classes 的目的是 "vectorize" 对应 Model
class 的方法。
我也在某些地方使用了 ModelList
,我希望允许 Model
的 childclass 或 ModelList
作为参数传递到一个函数。
ModelList
知道(并检查)其任何元素将被接受的类型。为了使 ModelList
childclass 知道其对应的 Model
child class,我将其定义为 class 变量 element_type
在 ModelList
child class.
每个ModelList
childclass都紧密耦合到一个Model
childclass:一个ModelList
class 属于一个 Model
class。这就是为什么我将 ModelList
child class 作为它们各自的 Model
class 的内部 classes。我的问题来了:因为 ModelList
需要知道 Model
并且 Model
需要知道 ModelList
并且在每个 class 的初始化期间,我有一个循环我的 classes 之间的依赖关系。
最小示例
我将我的代码减少到最小示例以使我的设计更容易理解:
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
不想解耦
我知道我可以通过解耦两个 classes 来摆脱循环依赖。但是我确实 想要 Model
class 知道它对应的 ModelList
class 我也想要 ModelList
class 知道它的 Model
class。每个 Model
class 应该有一个并且只有一个 List
附在它上面。
猴子补丁是否合适?
我知道我可以通过 "monkeypatching" 我的 Model
child class 像这样绕过依赖:
class SomeModel(Model):
pass
class SomeModelList(ModelList):
element_type = SomeModel
SomeModel.List = SomeModelList
我觉得这是设计缺陷的标志。我说不出为什么,但感觉 "wrong".
问题
- monkeypatching 在这里合适吗?或者它是否表明我的设计存在更深层次的概念问题?
- 还有哪些解决方案?
- 我如何重新设计以摆脱这种循环依赖(但仍保持 classes 的耦合)?
- 是否可以在稍后定义相应的
Model
childclass 时评估 element_type
?
如果您想让 SomeModelList 表现得像一个泛型,您应该提供元素 class 作为构造函数的参数并将其分配给那里的 self.element_type。
class ModelList(list):
def __init__(self, model, elements=None):
self.element_Type = model
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.element_type):
raise TypeError(
f"{self.__class__} accepts only instances of {self.element_type} as elements. `{val}` is not!")
# usage
modelList = ModelList(SomeModel,[instance1,instance2,instance3])
然后您可以通过将 class 方法添加到您的模型库 class 来概括这一点(假设您在模型之前定义了 ModelList):
class Model:
... your other methods ...
@classmethod
def List(self,elements=None):
return ModelList(self.__class__,elements)
# usage
class SomeModel(Model): pass
modelList = SomeModel.List([instance1,instance2,instance3])
我的设计
口头描述
我有一个classModel
,当然上面有一些方法。除此之外,我还有一个 class ModelList
,其 childclass 表示 Model
的 q child class 的实例列表。除其他外,ModelList
child classes 的使用是提供批量操作,这不同于仅将操作委托给 ModelList
的每个元素。因此,ModelList
child classes 的目的是 "vectorize" 对应 Model
class 的方法。
我也在某些地方使用了 ModelList
,我希望允许 Model
的 childclass 或 ModelList
作为参数传递到一个函数。
ModelList
知道(并检查)其任何元素将被接受的类型。为了使 ModelList
childclass 知道其对应的 Model
child class,我将其定义为 class 变量 element_type
在 ModelList
child class.
每个ModelList
childclass都紧密耦合到一个Model
childclass:一个ModelList
class 属于一个 Model
class。这就是为什么我将 ModelList
child class 作为它们各自的 Model
class 的内部 classes。我的问题来了:因为 ModelList
需要知道 Model
并且 Model
需要知道 ModelList
并且在每个 class 的初始化期间,我有一个循环我的 classes 之间的依赖关系。
最小示例
我将我的代码减少到最小示例以使我的设计更容易理解:
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
不想解耦
我知道我可以通过解耦两个 classes 来摆脱循环依赖。但是我确实 想要 Model
class 知道它对应的 ModelList
class 我也想要 ModelList
class 知道它的 Model
class。每个 Model
class 应该有一个并且只有一个 List
附在它上面。
猴子补丁是否合适?
我知道我可以通过 "monkeypatching" 我的 Model
child class 像这样绕过依赖:
class SomeModel(Model):
pass
class SomeModelList(ModelList):
element_type = SomeModel
SomeModel.List = SomeModelList
我觉得这是设计缺陷的标志。我说不出为什么,但感觉 "wrong".
问题
- monkeypatching 在这里合适吗?或者它是否表明我的设计存在更深层次的概念问题?
- 还有哪些解决方案?
- 我如何重新设计以摆脱这种循环依赖(但仍保持 classes 的耦合)?
- 是否可以在稍后定义相应的
Model
childclass 时评估element_type
?
如果您想让 SomeModelList 表现得像一个泛型,您应该提供元素 class 作为构造函数的参数并将其分配给那里的 self.element_type。
class ModelList(list):
def __init__(self, model, elements=None):
self.element_Type = model
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.element_type):
raise TypeError(
f"{self.__class__} accepts only instances of {self.element_type} as elements. `{val}` is not!")
# usage
modelList = ModelList(SomeModel,[instance1,instance2,instance3])
然后您可以通过将 class 方法添加到您的模型库 class 来概括这一点(假设您在模型之前定义了 ModelList):
class Model:
... your other methods ...
@classmethod
def List(self,elements=None):
return ModelList(self.__class__,elements)
# usage
class SomeModel(Model): pass
modelList = SomeModel.List([instance1,instance2,instance3])