Python变量在递归函数的for循环后丢失值

0 投票
4 回答
1512 浏览
提问于 2025-04-17 19:47

这是一个关于Python的问题吗?在一个递归函数中,变量在for循环后失去了值。这段代码是用来测试的。其实我是在解析XML。

def findversion(aNode, aList, aFlag):
    print "FindVersion ", aNode[0:1]
    print "Findversion ", aFlag
    if aNode[1].find('Software') != -1:
        aFlag = 1
        aList.append(aNode[1])
    if aFlag == 1 and aNode[0] == 'b':
        aList.append(aNode[1])
    print "Before for ", aFlag
    for elem in aNode[2:]:
        print "After for ", aFlag
        findversion(elem,aList,aFlag)

node = ['td', 'Software version']
node2 = ['b', '1.2.3.4' ]
node3 = [ 'td', ' ', node2 ]
node4 = [ 'tr', ' ', node, node3 ]
print node4

myList = list()
myInt = 0
findversion(node4,myList,myInt)
print "Main ",myList

在下面的程序输出中,我总是希望“for循环前”的输出和“for循环后”的输出是一样的。

程序输出:

['tr', ' ', ['td', 'Software version'], ['td', ' ', ['b', '1.2.3.4']]]
FindVersion  ['tr']
Findversion  0
Before for  0
After for  0
FindVersion  ['td']
Findversion  0

Before for  1
After for  0

FindVersion  ['td']
Findversion  0
Before for  0
After for  0
FindVersion  ['b']
Findversion  0
Before for  0
Main  ['Software version']

Python版本:

Python 2.7.3 (default, Dec 18 2012, 13:50:09)
[GCC 4.5.3] on cygwin
Type "help", "copyright", "credits" or "license" for more information.

4 个回答

0

这个 After 是来自于外层的 findversion 调用:

...
print Before for 0
start iterating over aNode
   first td:
     print After for  0
     call findversion
       print FindVersion  ['td']
       print Findversion  0
       find Software, set aFlag = 1
       print Before for 1            <---
       start iterating over aNode
       it's empty
   second td:
     print After for  0              <---
     ...
0

这不是一个错误。变量 aFlag 只是局部的,只在特定的函数调用中有效,因为它是按值传递的。当你的程序打印出 'Before for 1' 时,它并没有进入 for 循环,因为 aNode[2:] 是空的(那时 aNode 只有两个元素)。所以,它根本不会打印任何 'After for' 的内容,而是直接返回。

如果你把 'After for' 的打印语句放在 for 循环的后面,而不是放在循环里面,输出会更清晰。这样输出就会一致了。

print "Before for ", aFlag
for elem in aNode[2:]:    
    findversion(elem,aList,aFlag)
print "After for ", aFlag
0

让人困惑的输出是因为After for 0的结果来自于一个不同的递归调用(不是和上面Before for 0的输出是同一个调用)。

这里有一个你函数的版本,增加了一些额外的信息来跟踪递归调用的深度:

def findversion(aNode, aList, aFlag, i=1):
    print "FindVersion ", aNode[0:1], 'call:', i
    print "Findversion ", aFlag, 'call:', i
    if aNode[1].find('Software') != -1:
        aFlag = 1
        aList.append(aNode[1])
    if aFlag == 1 and aNode[0] == 'b':
        aList.append(aNode[1])
    print "Before for ", aFlag, 'call:', i
    for elem in aNode[2:]:
        print "After for ", aFlag, 'call:', i
        findversion(elem,aList,aFlag,i+1)

下面是新的输出,展示了我所说的内容:

FindVersion  ['tr'] call: 1
Findversion  0 call: 1
Before for  0 call: 1
After for  0 call: 1
FindVersion  ['td'] call: 2
Findversion  0 call: 2
Before for  1 call: 2         # this is from the recursive call
After for  0 call: 1          # this is from the original call
FindVersion  ['td'] call: 2
Findversion  0 call: 2
Before for  0 call: 2
After for  0 call: 2
FindVersion  ['b'] call: 3
Findversion  0 call: 3
Before for  0 call: 3
Main  ['Software version']

撰写回答