Search code examples
pythonhigher-order-functions

Higher order function Python walkthrough


def tracer(fn):
    def traced(x):
        print('Calling', fn, '(', x, ')')
        result = fn(x)
        print('Got', result, 'from', fn, '(', x, ')')
        return result
    return traced

def fact(n):
    if n == 0:
        return 1
    return n * fact(n-1)

new_fact = tracer(fact)
new_fact(2)

I used this code on pythontutor.com to better understand higher order functions, but i'm having difficulty understanding why new_fact(2) in step 8 is mapped to traced? In other words, how does the traced function know the argument is 2?


Solution

  • In Python, functions are objects too. When you call the tracer() function, it returns the nested traced() function; it is in fact creating a new copy of that function:

    return traced
    

    You stored that returned function object in new_fact, then called it:

    >>> tracer(fact)
    <function traced at 0x10644c320>
    >>> new_fact = tracer(fact)
    >>> new_fact
    <function traced at 0x10644c398>
    >>> new_fact(2)
    ('Calling', <function fact at 0x10644c230>, '(', 2, ')')
    ('Got', 2, 'from', <function fact at 0x10644c230>, '(', 2, ')')
    2
    

    You can do this with any function; store a reference to a function in another name:

    >>> def foo(): print 'foo'
    ... 
    >>> bar = foo
    >>> bar()
    foo