对方法递归的效果感到好奇吗

2024-06-16 13:15:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经编写了一个实例方法,它使用递归来找到特定的解决方案。它工作得非常好,除了我退出if-elif块的时候。我在IF块中调用函数本身。而且,我只有一个返回语句。这个方法的输出对我来说很奇怪。以下是代码和输出:

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.

我不明白的是,一旦我的剩余\u项列表为空,我就将数据分配给sched \u输出并返回它。但是,print语句的执行时间与递归执行的时间相同。我怎样才能避免这种情况

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


Tags: oftheselfrestoutputhereitemsare
3条回答

在递归函数的末尾有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.",依此类推

打印11次的原因是,您总是在函数末尾调用print,并且您要调用函数11次(这和你得到Rest of the items are: …11次的原因是一样的,这应该更加明显。)

通常,最好的解决方案是重新设计一些东西,这样就不用在函数内部执行print之类的“副作用”,只需返回一个值,然后调用方就可以对结果执行它想要的任何副作用。在这种情况下,打print11次电话并不重要;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的实现中,因此不需要更改调用方看到的接口。)

当您在函数完成之前调用自身中的create_schedule函数时,一旦它到达末尾,并且不需要再次调用自己,每个函数都会结束,并在函数末尾点击“After completely solving coming here.”

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

相关问题 更多 >