【发布时间】:2020-02-11 13:52:28
【问题描述】:
假设我有以下基础和孩子
class Base:
def __new__(cls, *args):
if cls is Base:
if len(args) < 2:
return Child1.__new__(Child1, *args)
return Child2.__new__(Child2, *args)
return super().__new__(cls)
def __init__(self, arg):
self.common_arg = arg
class Child1(Base):
def __init__(self, arg0=None):
super().__init__(arg0)
class Child2(Base):
def __init__(self, arg0, arg1, *args):
super().__init__(arg0 + arg1)
self.args = list(args).copy()
类之间显然存在循环依赖关系,但是,只要所有类都定义在同一个模块中,这不会导致任何问题。
现在,我应该如何将它们分成三个模块(在同一个包中)?
我做了三个文件的拆分:
package/
__init__.py
base.py
ch1.py
ch2.py
内容如下:
# base.py ############################################################
from . import ch1, ch2
class Base:
def __new__(cls, *args):
if cls is Base:
if len(args) < 2:
return ch1.Child1.__new__(ch1.Child1, *args)
return ch2.Child2.__new__(ch2.Child2, *args)
return super().__new__(cls)
def __init__(self, arg):
self.common_arg = arg
# ch1.py ############################################################
from . import base
class Child1(base.Base):
def __init__(self, arg0=None):
super().__init__(arg0)
# ch2.py ############################################################
from . import base
class Child2(base.Base):
def __init__(self, arg0, arg1, *args):
super().__init__(arg0 + arg1)
self.args = list(args).copy()
按照here 的建议,但它不起作用。
import package.ch1
加注
AttributeError: module 'package.base' has no attribute 'Base'
【问题讨论】:
-
不确定这是否是完全相同的问题,但我曾经遇到过依赖问题,我发现经典的 hack 将导入放在一个不带参数的函数中,只包含导入语句。
-
您不能导入使用需要其他尚未定义的类的类的模块。几乎可以肯定,您可以更有效地设计它。利用基类中的方法默认被继承类覆盖的事实,您不需要这种令人困惑的设计。
-
通常情况下,使用父类必须了解其子类及其实现的架构是一种反模式。你想用这个技巧解决什么具体任务?
-
无论你可以使用什么 hack,它都不能解决根本问题,即你的设计是错误的(wrt:基本的 OO 设计 - 基类不应该知道它们的子类 - 和依赖项处理 - 即使语言支持它,你仍然不应该有任何循环依赖。明显的 XY 问题(你问的是如何使错误的解决方案工作而不是解释问题背后 这个解决方案以及如何解决它),所以请编辑您的问题并解释实际用例,以便有人可能会提出更好的设计建议。
-
我同意你们所有人的观点,这种设计模式很复杂,尽管这是已经使用过的东西,例如在
scipy.signal.lti(docs.scipy.org/doc/scipy/reference/generated/…) 中。我使用这种模式的原因如下:Child1和Child2是Base的不同表示。它们会有很多通用的方法,但是方法的实现是不同的。客户端只需实例化Base并让代码找出哪个表示更适合Child1或Child2来解决该问题。
标签: python python-3.x python-module