gma*_*dau 6 python forward-declaration circular-reference python-3.x python-dataclasses
所以,我在一个文件中有这两个数据类:
@dataclass
class A:
children: List[B]
@dataclass
class B:
parent: A
Run Code Online (Sandbox Code Playgroud)
,这可以通过使用该__future__.annotations功能来实现。
然后我有另外两个文件,每个文件都有一堆对于我的项目来说是静态的每种类型的对象。
文件objects_A:
import objects_B
obj_a1 = A(
children=[
objects_B.obj_b1,
objects_B.obj_b2
]
)
Run Code Online (Sandbox Code Playgroud)
文件objects_B:
import objects_A
obj_b1 = B(
parent=objects_A.obj_a1
)
obj_b2 = B(
parent=objects_A.obj_a1
)
Run Code Online (Sandbox Code Playgroud)
显然,文件之间存在循环依赖问题,但即使它们位于同一个文件中,它也不起作用,因为一种类型的变量依赖于另一种类型的变量才能成功。
初始化B内部对象obj_a1也不起作用,因为self这里没有概念。
目前,我设置parent为None(针对类型提示),然后循环进行设置obj_a1:
for obj_b in obj_a1.children:
obj_b.parent = obj_a1
Run Code Online (Sandbox Code Playgroud)
大家有什么好主意吗?
不知道它是否有帮助,但是这些对象是静态的(它们在这些声明之后不会改变)并且它们具有某种父子关系(正如您肯定已经注意到的那样)。
如果可能的话,我希望将每种类型的变量放在不同的文件中。
小智 1
解决此问题的一种方法是使用基类作为前向声明的替代方法。
@dataclass
class ParentBase:
children: List[object]
@dataclass
class Child:
parent: ParentBase
@dataclass
class Parent(ParentBase):
children: List[Child]
parent = Parent(children=[])
child = Child(parent=parent)
parent.children.append(child)
Run Code Online (Sandbox Code Playgroud)
这会起作用。我已经children: List[object]在 中添加了ParentBase. 这对于此代码的工作来说并不是必需的,但如果您添加它,您的 IDE 可以在您开始访问child.parent..
这不会阻止任何人用 a 实例化Childa ParentBase。为了解决这个问题,你可以这样做:
@dataclass
class ParentBase(abc.ABC):
children: List[object]
@abc.abstractmethod
def __post_init__(self):
pass
@dataclass
class Child:
parent: ParentBase
@dataclass
class Parent(ParentBase):
children: List[Child]
def __post_init__(self):
pass
parent = Parent(children=[])
child = Child(parent=ParentBase()) # TypeError
child = Child(parent=parent)
parent.children.append(child)
Run Code Online (Sandbox Code Playgroud)
它可能过于防御性且样板代码过多。是否想让它更安全取决于您的团队的偏好。