【问题标题】:Python: Changing Values in a Dictionary Tree StructurePython:更改字典树结构中的值
【发布时间】:2014-10-01 20:48:35
【问题描述】:

我在 Python 中有一个树结构,其中每个节点都是一个列表 [dict,int]。字典指向孩子们。叶子是纯整数,没有列表来节省内存。现在我想通过一个常数因子来缩放每个节点中的整数值。我编写了以下递归函数,它采用根节点和因子:

def scale(node,factor):
    if type(node) != list:
        node *= factor;
    else:
        node[1] *= factor;
        for key in node[0]:
            scale(node[0][key],factor);

我的印象是离开节点没有因为这些 Python 引用/取消引用问题而改变。这是真的吗?

【问题讨论】:

  • 你测试过吗?为什么不寻找证据来支持您的“印象”
  • 我有一个规范化约束,即所有子节点整数的总和是父节点的整数。在缩放之前但不满足此约束。如果我正确地进行了数学运算,那么这两种情况都应该满足。而且问题似乎不会出现在树的更高级别。
  • if 语句的两个分支中添加一些print 语句。当你运行程序时,它会告诉你发生了什么。
  • 您能否提供一个minimal example,包括数据,以便其他人可以复制该问题?

标签: python dictionary reference tree dereference


【解决方案1】:

这句话和你想的不一样:

node *= factor

这只是乘以局部变量node,它不会修改你最初传入的dict值。int是不可变的,所以没有办法将一个传递给函数并让函数就地修改它.

本文详细介绍了名称和值在 Python 中的工作方式:Facts and Myths about Names and Values in Python

顺便说一句:检查类型的最佳方法是(如果必须的话)是:

if not isinstance(node, list):

【讨论】:

    【解决方案2】:

    这个 sn-p 解释了为什么叶节点(int 类型)没有更新:

    def f(x):
        print "got x", x
        x *= 10
        print "set x to", x
    
    >>> n = 123
    >>> f(n)
    got x 123
    set x to 1230
    >>> n
    123
    
    >>> l=[1]
    >>> f(l)
    got x [1]
    set x to [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    >>> l
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    

    所以你可以看到n 没有改变,因为在函数f(x) 中只更新了局部变量x。但是,列表 l 已更新,因为它是可变的。

    解决此问题的任何简单方法是将叶节点包装在 list(或其他可变类型)中并存储(和更新)叶值。然后你可以这样写scale()

    def scale(node,factor):
        if len(node) == 1:   # leaf node is a list containing a single int
            node[0] *= factor;
        else:
            node[1] *= factor;
            for key in node[0]:
                scale(node[0][key],factor)
    

    【讨论】:

      【解决方案3】:

      由于我不打算更改我的数据结构,我必须执行以下操作(在我看来,这是 Python 很糟糕的情况之一):

      def scale(node,factor):
          for key in node[0]:
              if type(node[0][key]) != list:
                  node[0][key] *= factor;
              else:
                  node[0][key][1] *= factor;
                  scale(node[0][key],factor);
      

      然后在调用递归之前单独更改root int。幸运的是,在这种情况下,可能会有额外的好处,那就是它应该更快,因为没有离开节点的函数调用......

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-10-15
        • 2015-02-08
        • 2020-07-06
        • 1970-01-01
        • 2022-11-24
        • 2016-05-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多