Skip to main content
 首页 » 编程设计

递归调用时python构造函数不返回None

2025年05月04日13jackei

下面的代码没有返回 None 而是一些神秘的“main_.link_list object”:

class link_list(object): 
    """a link list class""" 
    def __init__(self, list): 
        super(link_list, self).__init__() 
        pdb.set_trace() 
        if list==[]: 
            return None 
        else: 
            self.value = list[0] 
            self.next = link_list(list[1:len(list)]) 

测试代码打印'False':

l=link_list([1,2,3]) 
print l.next.next.next==None 

为什么?

请您参考如下方法:

.__init__() 并不是真正的构造函数。

__init__ as a constructor?

无论您是否从 .__init__() 返回 None,都会创建该对象。正如@Ignacio Vazquez-Abrams 在评论中指出的那样,Python 期望 None 作为 .__init__() 的返回值;无论如何你不能返回任何其他东西。如果您需要发出某种灾难性错误的信号,您应该引发异常。

在您的示例中,您可能应该有一个表示完整链表的类,带有“头”引用和“尾”引用,另一个类表示链表中的数据条目。然后可以通过检查 head 是否为 None 来测试链表类本身是否为空列表。

编辑:经过进一步思考,您的单类实现将起作用;只是我们需要在.__init__()中将.next设置为None。这是我对您的代码的编辑:

class link_list(object): 
    """a link list class""" 
    def __init__(self, lst): 
        super(link_list, self).__init__() 
        pdb.set_trace() 
        if len(lst) > 1: 
            self.value = lst[0] 
            self.next = link_list(lst[1:]) 
            print "id == %d, linked in %d" % (id(self), id(self.next)) 
        elif len(lst) == 1: 
            self.value = lst[0] 
            self.next = None 
            print "length-one case: id == %d" % id(self) 
        else: 
            self.value = None 
            self.next = None 
            print "length-zero case: id == %d" % id(self) 
 
l=link_list([1,2,3]) 
print l.next.next.next is None 

注意事项:

  • 我修复了缩进。

  • 我使用 lst 而不是 list 作为变量名,以免隐藏内置类型 list。

  • 我添加了一些打印语句来帮助您观察正在发生的事情。

编辑:并且,为了完整起见,这里是一个使用两个类的实现:一个表示列表并且可能是零长度的类,以及一个表示列表中的一个条目的类。 for 循环构建条目链,并且可以从任何序列(包括迭代器)构建列表;不使用切片,因此序列不必是列表。

class link_list_val(object): 
    """one value for a linked list""" 
    def __init__(self, value): 
        self.value = value 
        self.next = None 
 
class link_list(object): 
    """a link list class""" 
    def __init__(self, seq): 
        self.head = None 
 
        for value in seq: 
            x = link_list_val(value) 
            if self.head is None: 
                self.head = x; 
                cur = x 
            else: 
                cur.next = x 
                cur = x 
 
l=link_list([1,2,3]) 
print l.head.next.next.next is None 

编辑:这是另一个版本。这使用迭代来构建链接列表,而不是尾递归,但是使用单个类来构建。诀窍在于 .__init__() 函数需要知道它是在构建一个完整的链表,还是只是让一个实例用于构建一个链表;因此检查 seq 是 None。如果用户传入一个序列,.__init__() 会构建一个完整的链表,否则它只会创建一个实例作为链表中的一个链接。

class link_list(object): 
    """a link list class""" 
    def __init__(self, seq=None): 
        super(link_list, self).__init__() 
        if seq is None: 
            return 
        pdb.set_trace() 
        itr = iter(seq) 
        try: 
            self.value = next(itr) 
        except StopIteration: 
            self.value = None 
            self.next = None 
            return 
        cur = self 
        for value in itr: 
            cur.next = link_list() 
            cur = cur.next 
            cur.value = value 
        cur.next = None 
 
l=link_list([]) 
print l.next is None 
l=link_list([1,2,3]) 
print l.next.next.next is None 

首先我们从序列中得到一个新的迭代器。然后我们尝试使用 next() 从序列中提取一个值。如果失败,我们有一个零长度的链表并返回它;如果成功,我们将该值用作链表的头部,然后循环遍历序列中的其余值。

直接使用迭代器可能看起来很棘手,但我认为这是处理这种情况的最干净的方法,我们想从序列中拉出第一项,然后循环其余的,我们不想使用切片(因此只适用于实际列表)。