Python 递归函数中列表的返回元组

Python 递归函数中列表的返回元组,python,Python,我正在学习Python的递归。我定义了一个链表,其中每个节点都有项和下一项。我想写一个递归,把奇数和偶数放在一个单独的集合中 class LinkNode(object): """A node in a linked list.""" def __init__(self, item, next=None): """(LinkNode, object, LinkNode) -> NoneType Initialize this node to store item and

我正在学习Python的递归。我定义了一个链表,其中每个节点都有项和下一项。我想写一个递归,把奇数和偶数放在一个单独的集合中

class LinkNode(object):
"""A node in a linked list."""

def __init__(self, item, next=None):
    """(LinkNode, object, LinkNode) -> NoneType
    Initialize this node to store item and next.
    """
    self.item = item
    self.next = next

def odd_or_even(self):
    """(LinkNode) -> ([object], [object])
    Return a pair of lists: (odd number, even number.
    """
    if self is None:
        return ([], [])
    else:
        if (self.item % 2 == 1):
            odd_num = odd_num.append(self.item)
        else:
            even_num = even_num.append(self.item)
    if self.next is not None:
        self.next.odd_or_even()
    return (odd_num, even_num)
当我运行它时,我得到了以下错误:

文件C:\Program Files\Wing IDE 101 4.1\src\debug\tserver\u sandbox.py,第19行,奇数或偶数 builtins.UnboundLocalError:赋值前引用了局部变量'odd_num'

我应该在哪里初始化奇数、偶数,这样它就不会被覆盖

谢谢

    if (self.item % 2 == 1):
        odd_num = odd_num.append(self.item)
    else:
        even_num = even_num.append(self.item)
...
return (odd_num, even_num)

上面的代码部分设置奇数或偶数的值,但不能同时设置两者。然后它尝试返回奇数和偶数,这会为其中一个产生错误。如果在If语句之前将两者都初始化为None,则可以避免出现错误。但是,为了使语义起作用,您可能需要向函数中添加另一个参数,即来自上一级别的结果;在递归调用中,将刚刚计算的奇数或偶数向下传递到下一级;然后返回下一级的结果。但是,最好避免递归,而是让循环运行两次。

我认为有几种不同的方法可以使用

一种是使用全局变量。我并不推荐这样做,但它很容易理解,所以我先介绍一下:

even_num = [] # these should be at module level, but I'm not showing the class
odd_num = []  # so you'll have to imagine the indentation being correct

def odd_or_even(self):
    """(LinkNode) -> ([object], [object])
    Return a pair of lists: (odd number, even number.
    """
    if self.item % 2 == 1:
        odd_num.append(self.item)
    else:
        even_num.append(self.item)

    if self.next is not None:
        self.next.odd_or_even()
对代码的更改很小,主要是删除返回语句。我确实对self-being-None进行了初始检查,因为在方法中这是不可能的,除非调用方非常努力地实现它。还值得注意的是,我们不尝试直接分配给奇数或偶数,因为这将创建一个局部变量,而不是访问已经存在的全局变量。此解决方案的缺点是,您只能调用奇数或偶数一次,并使其正常工作。如果您想再次调用它,可能需要在另一个列表中重新初始化全局变量

这里有一个更好的方法,它创建偶数和奇数列表作为局部变量,然后在最后返回它们。这可能是您在代码中的目标,但是您缺少将递归调用的结果添加到列表中的步骤

def odd_or_even(self):
    even_num = []
    odd_num = []

    if self.item % 2 == 1:
        odd_num.append(self.item)
    else:
        even_num.append(self.item)

    if self.next is not None:
        next_even, next_odd = self.next.odd_or_even()
        even_num.extend(next_even)
        odd_num.extend(next_odd)

    return even_num, odd_num
这段代码的问题是创建和扩展列表是浪费。在递归的每个级别上,将创建两个新列表,即使在该级别只处理一个值。对于整个递归过程,更好的方法可以只使用两个列表:

def odd_or_even(self, lists=None):
    if lists is not None:
        even_num, odd_num = lists
    else:
        even_num = []
        odd_num = []

    if self.item % 2 == 1:
        odd_num.append(self.item)
    else:
        even_num.append(self.item)

    if self.next is not None:
        return self.next.odd_or_even((even_num, odd_num))
    else:
        return even_num, odd_num
这比以前的版本更有效,因为它在递归的所有级别上使用相同的列表。在其他一些编程语言中,这种类型的递归(所有的工作都在递归调用运行之前完成)比其他类型的递归效率更高。这是因为编译器可以优化函数的返回步骤,而只需重用堆栈帧。然而,Python并没有进行这样的尾部调用优化,因为它会弄乱堆栈跟踪,所以好处并没有那么大


需要考虑的另一件事是:您可以使用自己的链表类而不是Python列表来保存偶数和奇数值。我上面介绍的第二个和第三个解决方案都可以使用,但是如果您愿意以相反的顺序返回偶数和奇数值,那么第三个解决方案将最自然地使用。

非常感谢!我使用您建议的局部变量测试了代码,效果很好。