好奇一个方法的递归效果

时间:2018-03-30 17:38:35

标签: python recursion

我编写了一个实例方法,它使用递归来查找某个解决方案。除了我退出if-elif块的时候,它工作得很好。我在IF块中调用函数本身。另外,我只有一个return语句。该方法的输出对我来说很难理解。这是代码和输出:

def create_schedule(self):
    """
    Creates the day scedule for the crew based on the crew_dict passed.
    """   
    sched_output = ScheduleOutput()
    assigned_assignements = []
    for i in self.crew_list:
        assigned_assignements.extend(i.list_of_patients)

    rest_of_items = []
    for item in self.job.list_of_patients:
        if item not in assigned_assignements:
            rest_of_items.append(item)

    print("Rest of the items are:", len(rest_of_items))

    if len(rest_of_items) != 0:
        assignment = sorted(rest_of_items, key=lambda x: x.window_open)[0]
        # print("\nNext assignment to be taken ", assignment)
        output = self.next_task_eligibility(assignment, self.crew_list)
        if len(output) != 0:
            output_sorted = sorted(output, key=itemgetter(2))
            crew_to_assign = output_sorted[0][1]
            assignment.eta = output_sorted[0][4]
            assignment.etd = int(assignment.eta) + int(assignment.care_duration)
            crew = next((x for x in self.crew_list if x.crew_number == crew_to_assign), None)
            self.crew_list.remove(crew)
            crew.list_of_patients.append(assignment)
            crew.time_spent = assignment.etd
            self.crew_list.append(crew)

            self.create_schedule()
        else:
            print("*" * 80, "\n", "*" * 80, "\nWe were not able to assign a task so stopped.\n", "*" * 80, "\n", "*" * 80)

            sched_output.crew_output = self.crew_list
            sched_output.patients_left = len(rest_of_items)

    elif not rest_of_items:
        print("Fully solved.")
        sched_output.crew_output = self.crew_list
        sched_output.patients_left = 0

    print("After completely solving coming here.")
    return sched_output

这是输出:

Rest of the items are: 10
Rest of the items are: 9
Rest of the items are: 8
Rest of the items are: 7
Rest of the items are: 6
Rest of the items are: 5
Rest of the items are: 4
Rest of the items are: 3
Rest of the items are: 2
Rest of the items are: 1
Rest of the items are: 0
Fully solved.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.

我不明白的是,只要我的列表rest_of_items为空,我就会将数据分配给sched_output并返回它。但是,print语句的执行时间与递归完成的时间相同。我怎么能避免这个?

我的输出非常好。我想要做的就是了解这种行为的原因以及如何避免这种行为。

3 个答案:

答案 0 :(得分:3)

它打印11次的原因是你总是在函数结束时调用print,并且你正在调用该函数11次。 (这与你获得Rest of the items are: … 11次的原因相同,这应该更加明显。)

通常,最好的解决方案是重新设计事物,而不是在函数内部执行像print这样的“副作用”,只需返回一个值,然后调用者就可以对结果做任何副作用。 。在这种情况下,你打电话print 11次并不重要; print只会在来电者中发生一次。

如果无法做到这一点,您可以对此进行更改,以便当您位于堆栈顶部时仅print。但是在许多递归函数中,没有明显的方法可以在不传递更多信息的情况下解决这个问题:

def create_schedule(self, depth=0):
    # etc.
    self.create_schedule(depth+1)
    # etc.
    if not depth:
        print('After completely solving come here.')
    returns sched_output

最后一种方法是只包装递归函数,如下所示:

def _create_schedule(self):
    # etc.
    self._create_schedule()
    # etc.
    # don't call print
    return sched_output

def create_schedule(self):
    result = self._create_schedule()
    print('After completely solving come here.')
    return result

这通常只在您需要为递归过程进行一次性设置时才需要,但是在这里你想做一些一次性的后处理,这基本上是同样的问题,所以它可以解决同样的方式。

(当然这只是伪装的第一个解决方案,但它隐藏在create_schedule的实现中,所以你不需要改变调用者看到的接口。)

答案 1 :(得分:1)

当你在函数完成之前调用你自己的create_schedule函数时,一旦它已经结束并且不需要再次调用自己,每个函数都会结束,然后点击“完全解决后来到这里” 。“,在功能的最后。

这意味着每个函数在调用之后仍然在运行 - 只是停留在它自己调用的行 - 直到它们全部完成,这时暂停的函数可以完成它们的任务,打印出你的语句。 / p>

答案 2 :(得分:0)

在递归函数结束时有print("After completely solving coming here.")。对于每次递归,该行将执行一次。

考虑这个简单的例子,它重现了你的问题:

def foo(x):
    print("x = {x}".format(x=x))
    if x > 1:
        foo(x-1)
    print("Done.")

现在调用函数:

>>> foo(5)
x = 5
x = 4
x = 3
x = 2
x = 1
Done.
Done.
Done.
Done.
Done.

正如您所看到的,在最后一次致电foo(x=0)时,它会打印"Done."。此时,该函数将返回上一个调用,该调用也将打印"Done.",依此类推。