1# -*- coding: utf-8 -*-
2
3import dataclasses
4
5
6# ------------------------------------------------------------------------------
7# Method 1, 双向 reference
8#
9# 优点:
10#
11# - 简洁, 容易实现, 比较直观
12#
13# 缺点:
14#
15# - 因为循环引用, garbage collect 永远不会回收
16# - 因为循环引用, 对里面的值进行修改要特别小心, 因为所有的对象都是 mutable 的, 牵一发而动全身
17#
18# 使用条件: 数据只会被创建有限次数, 不会不断的创建很多导致内存溢出. 对象一旦生成, 就不会被修改.
19# ------------------------------------------------------------------------------
20@dataclasses.dataclass
21class Child:
22 child_attribute: str = dataclasses.field()
23 parent: "Parent" = dataclasses.field(init=False)
24
25
26@dataclasses.dataclass
27class Parent:
28 parent_attribute: str = dataclasses.field()
29 child: Child = dataclasses.field()
30
31 def __post_init__(self):
32 self.child.parent = self
33
34
35parent = Parent(
36 parent_attribute="this is parent",
37 child=Child(
38 child_attribute="this is child",
39 ),
40)
41
42print(parent.child.parent.parent_attribute)
43
44
45# ------------------------------------------------------------------------------
46# Method 2, 在初始化时将 parent 中所需的值传给 child 的 constructor
47#
48# 优点:
49#
50# - 简洁, 对 child 和 parent 的代码没有侵入性, 负面效果比较小
51#
52# 缺点:
53#
54# - 只能传属性, 无法从 child 调用 parent 的方法
55# - 实现起来麻烦, 需要在 constructor 中写很多代码
56#
57# 使用条件:
58# ------------------------------------------------------------------------------
59@dataclasses.dataclass
60class Child:
61 child_attribute: str = dataclasses.field()
62 parent_attribute: str = dataclasses.field()
63
64
65@dataclasses.dataclass
66class Parent:
67 parent_attribute: str = dataclasses.field()
68 child: Child = dataclasses.field()
69
70
71parent_attribute = "this is parent"
72parent = Parent(
73 parent_attribute=parent_attribute,
74 child=Child(
75 child_attribute="this is child",
76 parent_attribute=parent_attribute,
77 ),
78)
79
80print(parent.child.parent_attribute)
81
82
83# ------------------------------------------------------------------------------
84# Method 3, 凡是在 child 需要访问 parent 的地方, 都构造一个方法
85#
86# 优点:
87#
88# - 完全符合函数式编程的思想, child 和 parent 完全解耦, child 只需要知道 parent 的接口就可以了
89#
90# 缺点:
91#
92# - 相当于要把 parent 中所有的 attribute 和 method 在 child 中都实现一遍, 代码量大
93#
94# 使用条件: 需要严格遵守函数式编程的规范. parent 和 child 两个模块是由不同的人维护的, 两个模块之间的耦合度很低.
95# ------------------------------------------------------------------------------
96@dataclasses.dataclass
97class Child:
98 child_attribute: str = dataclasses.field()
99
100 def get_parent_attribute(self, parent: "Parent") -> str:
101 return parent.parent_attribute
102
103
104@dataclasses.dataclass
105class Parent:
106 parent_attribute: str = dataclasses.field()
107 child: Child = dataclasses.field()
108
109
110parent = Parent(
111 parent_attribute=parent_attribute,
112 child=Child(
113 child_attribute="this is child",
114 ),
115)
116print(parent.child.get_parent_attribute(parent))