简体   繁体   中英

Can't understand assignments and environments usage on this recursive function

I'm learning about optimization in Composing Programs . I have 3 functions. memo is for memoization technique, count is a wrapper, so every time fib is called a counter is activated. fib is just an implementation of Fibonacci with recursivity.

 def memo(f):
    cache = {}

    def memoized(n):
        if n not in cache:
            cache[n] = f(n)
        return cache[n]

    return memoized


def count(f):
    def counted(*args):
        counted.call_count += 1
        return f(*args)

    counted.call_count = 0
    return counted


def fib(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    return fib(n - 2) + fib(n - 1)

To call the functions, I assing count(fib) to counted_fib , so every call is recorded. And* fib *variable is reasigned (now, fib is memo(counted_fib) not the original function)

counted_fib = count(fib)
fib = memo(counted_fib)

My problem start when the function fib is called (eg fib(19) ) Everything works as it should be, but the recursion inside the original function ( return fib(n - 2) + fib(n - 1) ) trigger fib as memo(counted_fib) .

This is not a problem about something that is not working. I'm just trying to understand why it happens if one thing is declared before another.

If what you are confused about is the way that the fib name behaves when being reassigned from the original fib() function to being a variable calling memo(counted_fib , I think this article about python's namespace behavior will help.

Python programs are executed starting from the first statement. But even before that, the global namespace is loaded. So you assign the fib name to fib() . But later on, you change that assignment to memo(counted_fib) , and that last assignment is the one loaded with the global namespace once the program starts.

Hope it helps!

In python, everything is an Object, functions included.

When you declare def fib it creates an object call fib and this object is callable .

This callable is calling in self by reference.

When you re-declare fib = memo(counted_fib) this move the reference fib to another object. (in this case memo function)

The count() function keeps track of each time the fib function was called by incrementing a call_count variable which can be checked afterwards. Then memo(counted_fib) is used to provide caching facilities for the counted_fib function. It does so by maintaining a cache object that keeps track of already computed values, thus ensuring that expensive recursive calls to counted_fib will not be duplicated when its inputs are called multiple times. Since every time fib is called inside counted_fib , it gets counted, memo(countedfib) ensures that each counted_fib call will only run once and all its computations will get cached for future access. Thus, after assigning counted_fib it would be possible to make successive calls to fib without overwriting its original definition or spend more time in expensive recursive calls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM