Search code examples
pythonpython-3.xfunctionname-binding

Is it possible to bind a name inside a python function after the function has been compiled?


I know this pattern is would be very bad, I'm asking the question out of curiosity not because I'm planning on doing this in production code.

Suppose I define a function:

def function(x, y):
    return x + y + z

And the variable z doesn't exist in the module the function was defined.

Is it possible to import the function from another module and somehow manipulate the code object, or play some sort of dirty trick with a decorator, or something, in order to make it work correctly?

I've tried setting co_varnames and co_argcount to (x, y, z) and 3 respectively, but this still doesn't bind the name z to the argument it seems.

To be clear, I know if I define a global named z in the same module this works, I'm asking about importing this function and somehow making z bind to a variable I want, in a different module.


Solution

  • Maybe use the function's code to create a new function using different globals:

    # create module for demo
    with open('module.py', 'w') as f:
        f.write('''
    def function(x, y):
        return x + y + z
    ''')
    
    from module import function
    
    function = type(function)(function.__code__, globals())
    
    z = 100
    print(function(20, 3))
    

    Output (Try it online!):

    123
    

    Or if you want a different variable name, maybe indeed use a "decorator" that sets z to the value of your variable before calling the function:

    from module import function
    
    f = function
    def function(*args):
        f.__globals__['z'] = foobar
        return f(*args)
    
    foobar = 100
    print(function(20, 3))
    

    Try it online!