Nested Parent and Child

  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))