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

时间:2012-07-02 23:50:51

标签: python

以下代码不会返回None,而是一些神秘的“ main _。link_list对象”:

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

为什么?

2 个答案:

答案 0 :(得分:6)

.__init__()实际上不是构造函数。

__init__ as a constructor?

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

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

编辑:经过一番深思,你的单班实施将会奏效;只是我们需要在.next内设置None.__init__()。这是我对您的代码的编辑:

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 is 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()从序列中提取值。如果失败,我们有一个零长度的链表并返回它;如果成功,我们将该值用于链表的头部,然后循环遍历序列中的其余值。

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

答案 1 :(得分:1)

class Item(object):
    '''Linked list'''

    def __new__(cls, lst):
        '''Construct object (allocate the memory)'''
        if lst:
            return super(Item, cls).__new__(cls)

    def __init__(self, lst):
        '''Initialize object (already created)'''
        self.value = lst[0]
        self.next = self.__class__(lst[1:])

    def __repr__(self):
        '''Representate as string'''
        return "%s(%s) -> %s" % (
            self.__class__.__name__,
            self.value,
            repr(self.next)
        )

>>> items = Item([1,2,3])
>>> print items
Item(1) -> Item(2) -> Item(3) -> None
>>> items.next.next.next is None
True