为什么子节点就像静态属性一样?

时间:2017-03-03 16:09:56

标签: python tree python-3.5

我尝试在Python中实现树数据结构。这就是我到目前为止的结果:

class Node:
    """
    This class implements a node in a tree.

    # Arguments #
    metadata:dict=dict()    |   A dict to store metadata.
    subnodes:tuple=tuple()  |   A tuple to define subnodes.
    """

    def __init__(self, metadata={"label": None, "content": None, "description": None}, subnodes=list()):
        self.metadata = metadata
        self.subnodes = subnodes

    def __str__(self):
        return "[{label}] {content}".format(
            label=str(self["label"]),
            content=str(self["content"])
        )

    def __repr__(self):
        return "<{}>".format(str(self))

    def __len__(self):
        count = len(self.subnodes)

        for n in self.subnodes:
            print(n)
            count+=len(n.subnodes)

        return count

    def __contains__(self, o):
        # check if in subnodes of self
        if o in self.subnodes:
            return True

        # check if in subnodes (recursive)
        for n in self.subnodes:
            if o in n:
                return True

        return False

    def __getitem__(self, key):
        return self.metadata[key]

    def __setitem__(self, key, value):
        self.metadata[key] = value

    def __delitem__(self, key):
        del self.metadata[key]

    def __lt__(self, o):
        return self in o

    def __gt__(self, o):
        return o in self

    def append(self, o:"Node"):
        """
        Appends an object as children.

        # Arguments #
        o:Node  |   Node object.
        """

        self.subnodes.append(o)

    def insert(self, i:int, o:"Node"):
        """
        Inserts an object to given index.

        # Arguments #
        i:int   |   Index
        o:Node  |   Node object
        """

        self.subnodes.insert(i, o)

    def remove(self, o:"Node"):
        """
        Removes an object from subnodes.

        # Arguments #
        o:Node  |   Node object
        """

        self.subnodes.remove(o)

    def is_leafnode(self):
        """
        Is this node a leaf node?
        """

        return len(self) == 0

    def search(self, **query):
        """
        Searches tree with metadata.

        **query:dict    |   Searching query.
        """

        return [d for d in self.metadata if all(d.get(k, object()) == v for k, v in query.items())]

我通过append对象的Node函数添加子节点。但是,subnodes属性就好像它是静态属性一样。

我的期望是:

enter image description here

但是,所有对象的subnodes属性都会返回:

enter image description here

手动测试

我手动测试了它。我有6个Node个对象,如下所示:

  • 一个
  • B'/ LI>
  • C
  • d
  • ë
  • ˚F

我想实现上面演示的结构。所以我做了:

a.append(b) # a => b
a.append(c) # a => c

b.append(d) # b => d
b.append(e) # b => e

c.append(f) # c => f

但是,当我调用任何subnodes对象的Node属性时:

a.subnodes # [<[b] None>, <[c] None>, <[d] None>, <[e] None>, <[f] None>]
b.subnodes # [<[b] None>, <[c] None>, <[d] None>, <[e] None>, <[f] None>]
# ...
# rest is the same

环境

  • Python 3.5.1

1 个答案:

答案 0 :(得分:1)

您的问题似乎是由Default Parameter Value问题造成的。

这意味着在创建类subnodes=list()期间,定义__init__中的默认参数Node只进行了一次评估。从这一点开始,每当您实例化一个新对象时,相同的可变对象将被用作默认值。由于这是一个可变对象,无论何时向self.subnodes追加内容,实际上都是在修改默认值。在this question中有一个非常详细的讨论。

基本上,Python中的规则是从不使用可变数据类型作为默认参数值。相反,请使用None,并明确指定默认值,如下所示:

class Node:

    def __init__(self, metadata={"label": None, "content": None, "description": None}, subnodes=None):
      self.metadata = metadata
      if subnodes is None:
          self.subnodes = []
      else:
          self.subnodes = subnodes