【问题标题】:How can a for-loop that touches no important code change program output?一个不涉及重要代码的for循环如何改变程序输出?
【发布时间】:2014-04-29 22:24:35
【问题描述】:

我正在处理一个相对较大的 python 文件,并且正在添加下一个重要功能。但是,我注意到插入 ANY for 循环会改变程序的输出。

为了测试这一点,我输入了以下循环:

for fff in range(2):
    print 'test'

变量fff 没有出现在代码中的其他任何地方。输出通过一个名为trueRepeats 的列表进行迭代,该列表显然没有被这段代码触及(就此而言,也没有任何变量)。然而,无论我把这个循环放在代码的什么地方——甚至在声明trueRepeats之前;即使是导入后执行的第一个代码,输出也会发生变化。

编辑:这是完整的来源:BitBucket。我尝试添加循环的原始位置位于注释块 #4 下,但如前所述,它似乎在其他各种地方引起了问题。我也在存储库中的文件“example.py”上运行。如果没有循环,程序会在第 {4, 7} 行和 {1, 10} 行返回两次重复。通过循环,它返回 {2, 3} 和 {1, 10} 处的实例。

我知道这不需要太多代码,但在我诊断出问题所在之前,我什至不知道这是怎么可能的,这是我的问题: python 中的什么可以使独立的for循环影响仅涉及循环不涉及的变量的输出?

编辑 2: 当我谈论输出变化时,我不是在谈论循环打印出的两个“测试”行。这些可以用pass 代替,但我觉得print 的副作用会更少。

编辑 3: 经过进一步调查,这个问题比for 循环运行得更深,因此这个问题可能不太适合 StackOverflow,因为真正的问题似乎很多注意力不集中。注释掉这一行:

if flag == 5:
    print "TEST: " + str(key)

还更改了程序输出,就像注释掉一行的一部分一样,它只是将文字 + "Parent: " 附加到正在打印的字符串的末尾。向字符串添加文字等副作用似乎不正常,因此我需要进一步调查以找出 python 行为如此奇怪的原因。

【问题讨论】:

  • 对..如果没有代码显示,这将是毫无意义的。
  • 是的。没有多少人可以在这里为您提供帮助,因为显然这会以某种方式与您的代码交互,因此我们需要查看该代码以确定它是如何交互的。
  • 您确定您周围没有某个模块或其他代码的旧版本吗?尝试从代码中删除循环,将所有文件保存在编辑器/IDE 中,然后在命令行中使用python ... 运行它们。然后添加循环,保存所有内容,然后从命令行再次运行。这避免了使用缓存在某些交互式会话中的任何旧模块。当然,您确实希望输出发生变化——您正在添加print 'test',它将打印test
  • 如果您多次运行代码而不更改任何内容,输出是否保持不变? (由于散列函数随机化,即使不使用random,它也会发生变化。)
  • 除非你能给我们一个最小的可重现的例子,否则任何人都很难提供帮助。一些不包含我们可能没有的 python 模块的东西,并且在不让 bug 消失的情况下尽可能小。是否可以删除任何代码以缩短它?即使只是用模拟结果替换对模块函数的调用并查看发生了什么,也可以帮助您追踪受到影响的代码。

标签: python for-loop output


【解决方案1】:

无论您的代码的其余部分是什么,该循环都会打印出两次“测试”。 为什么?因为 for 循环不需要变量,“fff”只是一个用于迭代的占位符。 我可以有这个代码:

def add(a, b):
    print a + b
add(5, 5)
for fff in range(2):
    print "test"

输出将是:

10testtest

【讨论】:

  • 我已经添加了一个澄清:当我在上面谈到输出变化时,我没有包括打印出来的两个新行——我选择使用print作为@中的动作987654324@ 循环,希望它的副作用比pass 少。我说的是程序的算法输出
  • 哦,那肯定很奇怪。也许这与额外的计算时间有关?
【解决方案2】:

我认为这是您代码中的错误:

alphaset = set() ## 1
...
for i in range(len(partition)):
    for j in range(len(partition[i])):
        alphaset.add(type(partition[i][j])) ## 2
        nodecount += 1
...
count = 0
mapping = dict()
for elem in alphaset: ## 3
    mapping[elem] = count ## 4
    count+=1

alphasize = count
...
for i in range(len(partition)):
    j = len(partition) - i - 1
    ...
    for v in range(len(partition[j])):
        node = partition[j][v]

        SV = list()
        SV.append(mapping[type(node)]) ## 5

这就是发生的事情。在 1 处,您有一个在 2 处填充的集合,其中一些类型来自具有特定“顺序”的列表。然后,在 3 和 4 处,您遍历集合并将 set 中的每个元素映射到某个数字。然后,在 5 处,该数字被添加到列表中。如果我正确理解了您的代码,则其余代码取决于该列表中元素的“顺序”,这取决于映射,而映射本身取决于集合中元素在 1 处的顺序。

现在,不能保证set 中元素的顺序,也不能保证它的迭代顺序。因此,在 3 和 4 处,对于不同的运行,您将获得不同的映射。

解决方案是将set 显式排序为list,或使用保留插入顺序的OrderedSet(假设第1 点之前的代码始终以相同的顺序插入节点)。

【讨论】:

  • 小心//不是python中的cmets,它的#
  • 嗯.. 这是故意的,所以这些数字不会与 sn-p 中的原始 cmets 混淆:-)。
  • 复制和粘贴像我这样的尼安德特人感到困惑。
猜你喜欢
  • 2019-05-31
  • 2019-09-20
  • 2023-03-22
  • 2020-03-27
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
相关资源
最近更新 更多