For simple cases, such as when the code is short and we don't have many variables to capture, we can create a temporary lambda and call it:
def f():
    a = 1
    g = (lambda a: lambda: a)(a)
    a = 2
    return g
The issue here is that the code can quickly become harder to read.
Alternatively, we can capture the variable as an optional argument:
def f():
    a = 1
    g = lambda a=a: a
    a = 2
    return g
The issue here is, of course, that we might not want the caller to be able to specify this parameter.
(And the code can be a little less readable, too.)
A fully general solution might be the following, except that it does not capture globals:
def bind(*args, **kwargs):
    # Use '*args' so that callers aren't limited in what names they can specify
    func               = args[0]
    include_by_default = args[1] if len(args) > 1 else None
    # if include_by_default == False, variables are NOT bound by default
    if include_by_default == None: include_by_default = not kwargs
    fc = func.__code__
    fv = fc.co_freevars
    q = func.__closure__
    if q:
        ql = []
        i = 0
        for qi in q:
            fvi = fv[i]
            ql.append((lambda v: (lambda: v).__closure__[0])(
                kwargs.get(fvi, qi.cell_contents))
                if include_by_default or fvi in kwargs
                else qi)
            i += 1
        q = q.__class__(ql)
        del ql
    return func.__class__(fc, func.__globals__, func.__name__, func.__defaults__, q)
The reason I do not attempt to capture globals here is that the semantics can get confusing -- if an inner function says global x; x = 1, it certainly does want the global x to be modified, so suppressing this change would quickly make the code very counterintuitive.
However, barring that, we would be able to simply use it as follows:
def f():
    a = 1
    g = bind(lambda: a)
    a = 2
    return g
print(f()())
And voilĂ , a is instantly captured. And if we want to only capture some variables, we can do:
def f():
    a = 1
    b = 2
    g = bind(lambda: a + b, b=5)  # capture 'b' as 5; leave 'a' free
    a = 2
    b = 3
    return g
print(f()())