Function decorator that caches function results

Fredrik Lundh fredrik at pythonware.com
Sun Oct 9 11:12:00 EDT 2005


Ron Adam wrote:

> In effect, 'cache' and 'fn' are replaced by the objects they reference
> before the cached_result function is returned.

not really; accesses to "free variables" always go via special cell objects
(rather than direct object references), and the compiler uses special byte
codes for all accesses to such objects.

this snippet illustrates the differences:

def func1():
    return a

def func2(a):
    return a

def wrapper(a):
    def func3():
        return a
    return func3

def decode(func):
    import dis
    print func.__name__ + ":"
    dis.dis(func)
    print "co_freevars =", func.func_code.co_freevars
    print "func_closure =", func.func_closure
    print

decode(func1)
decode(func2)
decode(wrapper(10))

if you run this on a recent version of Python, you get something like:

    func1:
      2           0 LOAD_GLOBAL              0 (a)
                  3 RETURN_VALUE
    co_freevars = ()
    func_closure = None

    func2:
      5           0 LOAD_FAST                0 (a)
                  3 RETURN_VALUE
    co_freevars = ()
    func_closure = None

    func3:
      9           0 LOAD_DEREF               0 (a)
                  3 RETURN_VALUE
    co_freevars = ('a',)
    func_closure = (<cell at 0x0092C970: int object at 0x008A537C>,)

note the use of LOAD_DEREF for the variable access.

Other opcodes include STORE_DEREF (that updates a local variable
through a cell, used inside the "defining" scope), and MAKE_CLOSURE
(which sets up the function object for functions that actually uses
nested scopes; this is where the func_closure attribute is initialized).

(now, if I weren't limited to plain text, I could have drawn a nice little
diagram for you, but that's an entirely different thread...)

</F>






More information about the Python-list mailing list