Tree数据结构中的Python递归对象引用

时间:2018-05-25 09:49:08

标签: python python-3.x object tree object-reference

我对python不熟悉。我需要使用树来存储一些数据(文件路径),问题是当我生成树时,似乎所有对象在根之后引用相同的对象,尽管逐步调试显示相反的情况。这是我的(最小化)代码: 首先是节点类:

class PathElement:  

  Element = ""
  IsStatic = True
  Children = []
  ChildrenCount = 0 

  def __init__(self, Element, IsStatic=True):
      self.Element = Element
      self.IsStatic = IsStatic
      if not IsStatic:
          self.Element = [] 

  def AddChild(self, Child):
      print(self, "    ", Child)
      self.Children.append(Child)
      self.ChildrenCount = len(self.Children)
      return Child

Children是PathElement节点的列表。构建树的代码:

def UnFoldAndCheck(self):
    Path = PathElement("root")
    Handler = Path
    Index = 0
    Count = len(self.Path)
    while Index < Count:

        element = self.Path[Index]

        if something:
            Child = None
            Child = PathElement(element)
            Handler.AddChild(Child)
            Handler = None #Those added to debug the problem
            Handler = Child
        elif other_thing:
            if condition:
                if some_large_condition:
                    ChildExec = None
                    ChildExec = PathElement(element, False)
                    for i in range(0, 5):
                        ChildExec.Element.append(self.Path[Index + i])
                    Handler.AddChild(ChildExec)
                    Handler = None
                    Handler = ChildExec
                    Index += 4
            elif another_condition:
                ChildOp = None
                ChildOp = PathElement(element, False)
                Handler.AddChild(ChildOp)
                Handler = None
                Handler = ChildOp
            elif some_else_condition:
                 if condition:
                    ChildExec = None
                    ChildExec = PathElement(element, False)
                    for i in range(0, 3):
                        ChildExec.Element.append(self.Path[Index + i])
                    Handler.AddChild(ChildExec)
                    Handler = None
                    Handler = ChildExec
                    Index += 2

                elif different_condition:
                    ChildExec = None
                    ChildExec = PathElement(element, False)
                    for i in range(0, 3):
                        ChildExec.Element.append(self.Path[Index + i])
                    Handler.AddChild(ChildExec)
                    Handler = None
                    Handler = ChildExec
                    Index += 1
        Index += 1
    return Path

我的问题是,在我使用它之后构建树时,它将始终具有相同的结构: root - &gt;具有3个精确节点的对象 - &gt;相同的对象 - &gt;同一个对象到无穷大 而期望是: root - &gt;对象 - &gt;第一个孩子 - &gt;第二个孩子 - &gt;第三个孩子 - &gt;等等 我确定问题与python如何处理对象引用有关但我无法确切地看到问题所在。有帮助吗?

更新

我用较小的代码(同一类PathElement)重现了这个问题:

from PathElement import PathElement
Path = PathElement("root")
Handler = Path
for i in range(1,6):
   Child = PathElement("child"+str(i))
   Handler.AddChild(Child)
   Handler = Child
Tree = Path
while True:
   print(Tree.Element)
   if len(Tree.Children) > 0:
      Tree = Tree.Children[0]
   else:
       break

此代码将进行无限循环

1 个答案:

答案 0 :(得分:1)

我猜你来自Java或类似的语言。坚持使用Python的惯例非常重要(Jakob Sachs为您提供了Style Guide for Python Code的链接),因为这样可以更容易识别您的错误。

现在,这里有什么问题?当你写道:

Children

您没有提供实例字段的初始值。 您创建初始化类(静态)字段。因此,PathElement是类class A(): i = [] a = A() b = A() a.i.append(1) b.i.append(2) assert a.i == b.i == [1,2] 的静态字段。这是一个例子:

while True:
   print(Tree.Element)
   if len(Tree.Children) > 0:
      Tree = Tree.Children[0]
   else:
       break

当你尝试读取树的最左边部分(孩子0,孩子0的孩子0,......)时会发生什么?

Tree.Children

只需将PathElement.Children替换为真实的内容:Children,即类PathElement的静态字段while True: print(Tree.Element) if len(PathElement.Children) > 0: Tree = PathElement.Children[0] # Tree has always the same value. else: break

class PathElement:  
    def __init__(self, element):
        self.__element = element
        self.__children = []

    def add_child(self, child):
        self.__children.append(child)

    def children(self):
        return list(self.__children)

    def element(self):
        return self.__element

path = ["a", "b", "c", "d", "e", "f"]

root = PathElement("root")
handler = root
while path:
    child = PathElement(path.pop(0)) # you can put some conditions here, take more elements of path, ...
    handler.add_child(child)
    handler = child

def dfs(node):
    for c in node.children():
        yield c.element()
        yield from dfs(c)

print (list(dfs(root)))
# a b c d e f

现在,您可以写一个例子:

import keras
from keras.preprocessing import image
from keras.applications.resnet50 import preprocess_input

model = keras.models.Sequential()
model.add(keras.layers.Lambda(preprocess_input, name='preprocessing', input_shape=(224, 224, 3)))

file = '/path/to/an/image.jpeg'
x = np.array(image.img_to_array(image.load_img(file, target_size=(224, 224))))

preprocessed_x = preprocess_input(x)
predicted_x = model.predict(x.reshape(1,224,224,3)).reshape(224,224,3)