回调的简单实现:如何停止堆栈增长?

Naive implementation of a callback: How do I stop the stack growing?

我刚刚了解了回调的概念,我决定尝试实现自己的回调。我的努力卓有成效,我确实设法模拟了回调的功能。不幸的是,我注意到我的实现导致堆栈在每个周期增加 2 个函数调用,我认为如果代码 运行 的时间足够长,最终会导致堆栈溢出。

我想知道,我如何实现这段代码来防止堆栈在每个周期都增长?或者这是这个实现的必然产物,在这种情况下如何规避这个问题?

import time
import inspect 

def doSomething(x):
    return x + 0.00000001

def continue_processing(runningTotal,termination_condition,callback,callback_args,timeout=5):
    startTime = time.time()
    while (time.time() - startTime < timeout and not(termination_condition(runningTotal))):
        runningTotal = doSomething(runningTotal)

    print(f"Returning control to calling function, running total is {runningTotal}")
    return callback(runningTotal,*callback_args)

def process(runningTotal,n,beginTime):

    if(runningTotal < n):
        print(f"Continue processing, running total is {runningTotal}\nTime elapsed {time.time() - beginTime}\nCurrent stack size: {len(inspect.stack())}")
        continue_processing(runningTotal,lambda x: x>n,process,(n,beginTime))

if __name__ == '__main__':

    beginTime = time.time()
    try:
        process(0,1,beginTime)
    except KeyboardInterrupt:
        print("Program interrupted!")
        exit(0)
    print(f"Completed in {time.time() - beginTime}"

问题在于回调是递归的,它会(间接地)调用自身——这就是堆栈溢出的原因。下面是如何避免这种情况。请注意,我还更改了您的代码以符合 PEP 8 - Style Guide for Python Code 准则以使其更具可读性。我强烈建议您阅读并遵循它,特别是如果您只是在学习这门语言。

import time
import inspect


def doSomething(x):
    return x + 0.00000001

def continue_processing(runningTotal, termination_condition, timeout=5):
    startTime = time.time()
    while (time.time() - startTime < timeout
            and not(termination_condition(runningTotal))):
        runningTotal = doSomething(runningTotal)

    print(f"Returning control to calling function, running total is "
          f"{runningTotal}")

    # Don't call back the callback
    #return callback(runningTotal, *callback_args)

def process(runningTotal, n, beginTime):
    while runningTotal < n:
        print(f"Continue processing, running total is {runningTotal}\n"
              f"Time elapsed {time.time() - beginTime}\n"
              f"Current stack size: {len(inspect.stack())}")
        continue_processing(runningTotal, lambda x: x>n)


if __name__ == '__main__':

    beginTime = time.time()
    try:
        process(0, 1, beginTime)
    except KeyboardInterrupt:
        print("Program interrupted!")
        exit(0)
    print(f"Completed in {time.time() - beginTime}")