Python 如何将父母和子女相互链接?

Python 如何将父母和子女相互链接?,python,parent-child,parent,children,Python,Parent Child,Parent,Children,有两个简单的类;一个仅具有父属性属性,另一个同时具有父属性和子属性属性。 这意味着同时具有父项和子项的一个继承自仅具有父项的一个 这是一个只有parent属性的类。 我们称它为Child,因为它只能是子对象,不能是父对象。 我将使用一个方法set\u parent()使其更清晰,但我会在实际代码中使用setter class Child(object): def __init__(self, parent=None): self.__parent = None

有两个简单的类;一个仅具有
父属性
属性,另一个同时具有
父属性
子属性
属性。 这意味着同时具有
父项
子项
的一个继承自仅具有
父项
的一个

这是一个只有
parent
属性的类。 我们称它为
Child
,因为它只能是子对象,不能是父对象。 我将使用一个方法
set\u parent()
使其更清晰,但我会在实际代码中使用setter

class Child(object):

    def __init__(self, parent=None):
        self.__parent = None
        self.set_parent(parent)

    def set_parent(self, parent):
        # Remove self from old parent's children
        if self.__parent:
            self.__parent.remove_child(self)
        # Set new parent
        self.__parent = parent
        # Add self to new parent's children
        if self.__parent:
            self.__parent.add_child(self)
这段代码非常有意义,似乎工作得很好。 也就是说,如果父类看起来像这样简单:

class Parent(Child):

    def __init__(self, parent=None):
        super(Parent, self).__init__(parent)
        self.__children = []

    def add_child(self, child):
        if child not in self.__children:
            self.__children.append(child)

    def remove_child(self, child):
        if child in self.__children:
            self.__children.remove(child)
但是,我希望能够调用
my\u parent.add\u child(my\u child)
,并将
my\u child
的parent属性设置为
my\u parent
,同时将
my\u child
从其旧家长的孩子中删除

我似乎不知道如何实际设计代码,我尝试的每件事都会在
set\u parent()
add\u child()
remove\u child()
之间变成一个无限循环

我知道这个网站不适合其他人为我写代码,但至少有人能给我一些提示吗? 我的大脑无法处理这个问题,我已经连续思考了30分钟,但什么都没做。
谢谢你的帮助

在讨论当前的问题之前,有几件事需要用python编码来解决。首先,您可能不希望在实例属性名称前面加上双下划线。Python将通过在属性名前加类名来破坏属性名,这可能会导致意外的效果

Class A(object):
    def __init__(self):
        self.__myvar = 5

a = A()

print a.__myvar
>>> AttributeError: 'A' object has no attribute '__myvar'

print a._A__myvar
>>> 5
接下来,您似乎正在尝试构建类似于。为了完成这项任务,没有必要为孩子和家长设立单独的班级。您应该能够对这两个类使用相同的类!您似乎已经意识到,Python没有原生树数据结构,因此大多数人倾向于构建自己的树数据结构。您还可以看到人们为非本机数据结构制作的一些包

最后,对于一个厚颜无耻(并且有点混乱)的python树实现,请检查。有一个更有用的版本,子类
defaultdict
,但是我现在似乎找不到它

好吧,那就谈正事吧。我已将您的
子类
父类
合并为一个
节点
类。您可以忽略
名称
\uuuuuu str\uuuuuuuuu
\uuuuuuu repr\uuuuuuuuuu
定义,因为我只是使用这些定义来跟踪发生了什么

class Node(object):

    def __init__(self, name, parent=None):
        self.name = name
        self._parent = None
        self._children = []
        self.set_parent(parent)

    def add_child(self, other):
        if not self.has_child(other):
            self._children.append(other)

        if not other._parent == self:  # Prevents infinite loop
            other.set_parent(self)

    def remove_child(self, other):
        idx = self._children.index(other)
        return self._children.pop(idx)

    def set_parent(self, other):
        if self._parent is not None:
            if self._parent.has_child(self):
                self._parent.remove_child(self)

        self._parent = other

        if isinstance(other, Node):
            other.add_child(self)

    def has_child(self, child):
        if child in self._children:
            return True
        return False

    def __str__(self):
        return "<Node {}>".format(self.name)

    def __repr__(self):
        return self.__str__()
类节点(对象):
def uuu init uuu(self,name,parent=None):
self.name=名称
self.\u parent=None
self._children=[]
self.set\u父(父)
def添加_子项(自身、其他):
如果没有自己的孩子(其他):
self.\u children.append(其他)
如果不是其他。_parent==self:#防止无限循环
其他。设置父项(自身)
def移除_子项(自身、其他):
idx=自我。\u子项索引(其他)
返回self.\u children.pop(idx)
def set_父级(自身、其他):
如果self.\u parent不是None:
如果self.\u父母有子(self):
self.\u父项。删除子项(self)
self.\u parent=其他
如果isinstance(其他,节点):
其他。添加子对象(自身)
def有子项(自我、子项):
如果孩子在自己身上。\u孩子:
返回真值
返回错误
定义(自我):
返回“”。格式(self.name)
定义报告(自我):
返回自我
现在来测试一下,确保一切正常

p = Node('p')
c1 = Node('c1', p)
c2 = Node('c2', c1)

print p, ':', p._parent, p._children
print c1, ':', c1._parent, c1._children
print c2, ':', c2._parent, c2._children

>>> <Node p> : None [<Node c1>]
>>> <Node c1> : <Node p> [<Node c2>]
>>> <Node c2> : <Node c1> []

p.add_child(c2)
print p, ':', p._parent, p._children
print c1, ':', c1._parent, c1._children
print c2, ':', c2._parent, c2._children

>>> <Node p> : None [<Node c1>, <Node c2>]
>>> <Node c1> : <Node p> []
>>> <Node c2> : <Node p> []

c1.set_parent(c2)
print p, ':', p._parent, p._children
print c1, ':', c1._parent, c1._children
print c2, ':', c2._parent, c2._children

>>> <Node p> : None [<Node c2>]
>>> <Node c1> : <Node c2> []
>>> <Node c2> : <Node p> [<Node c1>]
p=Node('p')
c1=节点('c1',p)
c2=节点('c2',c1)
打印p',:',p.\父项,p.\子项
打印c1',:',c1.\父项,c1.\子项
打印c2',:',c2.\父项,c2.\子项
>>>:无[]
>>>  :  []
>>>  :  []
p、 添加子项(c2)
打印p',:',p.\父项,p.\子项
打印c1',:',c1.\父项,c1.\子项
打印c2',:',c2.\父项,c2.\子项
>>>:无[,]
>>>  :  []
>>>  :  []
c1.设置父项(c2)
打印p',:',p.\父项,p.\子项
打印c1',:',c1.\父项,c1.\子项
打印c2',:',c2.\父项,c2.\子项
>>>:无[]
>>>  :  []
>>>  :  []

希望这能解决你的问题。我还没有对此做过详尽的测试,所以如果您遇到任何问题,请告诉我。

马丁·福勒(Martin Fowler)、肯特·贝克(Kent Beck)和其他几位作者在《重构:改进现有代码的设计》一书中描述了这个问题,称之为“双向关联”。书中解决这个问题的方法是给其中一个类分配一个对另一个类的完全控制。首先,您需要决定此处必须由哪个类控制。我相信在你的情况下,孩子应该控制自己,这与现实世界的运作方式是背道而驰的。然后,您需要允许控制器访问受控对象的私有成员。在C++中,你可以通过使一个类成为另一个“朋友”来解决这个问题。在其他具有真正隐私的语言中,您可以创建一个公共访问器方法,并在文档中明确说明它只供一个类使用。然而,在Python中,您并没有受到这样的限制。考虑下面的代码:

class Child(object):
    def __init__(self, parent=None):
        self._parent = None
        self.set_parent(parent)

    def set_parent(self, parent):
        # Remove self from old parent's children
        if self._parent:
            self._parent._children.remove(self)
        # Set new parent
        self._parent = parent
        # Add self to new parent's children
        if self._parent:
            self._parent._children.append(self)


class Parent(Child):
    def __init__(self, parent=None):
        super(Parent, self).__init__(parent)
        self._children = []

    def add_child(self, child):
        if child not in self._children:
            child.set_parent(self)

    def remove_child(self, child):
        if child in self._children:
            child.set_parent(None)


c1 = Child()
c2 = Child()
p1 = Parent()
p2 = Parent()

p1.add_child(c1)
p1.add_child(c2)
print "1:"
print "c1._parent", c1._parent
print "c2._parent", c2._parent
print "p1._children", p1._children
print "p2._children", p2._children
p2.add_child(c1)
print "2:"
print "c1._parent", c1._parent
print "c2._parent", c2._parent
print "p1._children", p1._children
print "p2._children", p2._children

c1 = Child()
c2 = Child()
p1 = Parent()
p2 = Parent()

c1.set_parent(p1)
c2.set_parent(p1)
print "3:"
print "c1._parent", c1._parent
print "c2._parent", c2._parent
print "p1._children", p1._children
print "p2._children", p2._children
c1.set_parent(p2)
print "4:"
print "c1._parent", c1._parent
print "c2._parent", c2._parent
print "p1._children", p1._children
print "p2._children", p2._children
parent.add\u child(child)
child.set\u parent(parent)
应该是相同的操作。让其中一个委托给另一个,或者让两个都委托给第三个方法,或者只是删除其中一个。这会使事情更容易推理

快速而肮脏的方法是
\u add\u child
方法,该方法在不接触子对象的
父属性的情况下添加子对象。您的
set\u父项可以使用它来避免无限递归。但是,像
\u add\u child
或您当前的
remove\u child
这样的方法很容易出错,因为它们破坏了对称性