假设我有两个这样的类:
class Root:
def __init__(self):
self.children = []
class Child:
def __init__(self):
# How do I make this attribute (or property if I must change
# it to one) automatically reference the root object (if the
# current object is a an item of root.children)
self.root = ???
所以我的问题部分已经存在于代码中,但需要澄清一下。假设我从类中创建对象:
root_obj = Root()
child_obj = Child()
root_obj.children.append(child_obj)
如何使child_obj.root
自动检测到当前对象存储在root_obj
下并引用该对象?这样,如果我稍后决定将child_obj
存储在新对象another_root_obj.children
中,则child_obj.root
将引用该对象。如果这不可能像我尝试的那样,那么在Python中设计这样的系统的正确方法是什么?
答案 0 :(得分:1)
对象不会跟踪引用它的内容。主要是因为这很少需要,并且会增加garabage集合的复杂性。所以这是你必须自己实施的行为。
以下解决方案直接实施将更新add_child
根的remove_child
和Child
方法。
class Root:
def __init__(self):
self.children = set()
def add_child(self, child):
self.children.add(child)
child.roots.add(self)
def remove_child(self, child):
if child in self.children:
self.children.remove(child)
child.roots.remove(self)
class Child:
def __init__(self):
self.roots = set()
root_obj = Root()
child_obj = Child()
root_obj.add_child(child_obj)
child_obj.roots # {<__main__.Root object at 0x000001FDD5406048>}
root_obj.remove_child(child_obj)
child_obj.roots # set()
答案 1 :(得分:1)
无法自动检测是否附加到列表中。
以下两种方法足够接近。你只需要一个:
类似ORM的save(self)
函数。
不要将子项附加到root,而是将root用户分配给具有Pythonic @property
和setter
的子项。
class Root:
def __init__(self):
self.children = []
#1
def save(self):
for child in self.children:
child.root = self
class Child:
def __init__(self):
self.__root = None
#2
@property
def root(self):
return self.__root
#2
@root.setter
def root(self, root):
self.__root = root
if self not in root.children:
root.children.append(self)
#1的用法:
root_obj = Root()
child_obj = Child()
root_obj.children.append(child_obj)
root_obj.save()
print(child_obj.root) # <__main__.Root object at 0x05932890>
#2的用法:
root_obj = Root()
child_obj = Child()
child_obj.root = root_obj
print(root_obj.children) # [<__main__.Child object at 0x060578F0>]
如果将两者结合使用,则可以轻松处理:
child_obj.root = root_obj_2
child_obj.root = None
root_obj.children.remove(child_obj)
然后root_obj.save()
class Root:
def __init__(self):
self.children = []
self.__previous_children = []
def save(self):
diff = [c for c in self.__previous_children if c not in self.children]
if len(diff) == 0 and len(self.__previous_children) == len(self.children):
return
for child in diff:
child.root = None
self.__previous_children = self.children.copy()
for child in self.children:
child.root = self
class Child:
def __init__(self):
self.__root = None
@property
def root(self):
return self.__root
@root.setter
def root(self, root):
if self.__root == root:
return
if self.__root is not None:
try:
self.__root.children.remove(self)
self.__root.save()
except:
pass
self.__root = root
if root is None:
return
if self not in root.children:
root.children.append(self)
root.save()