Instantiating functions and modules

In Python, anything that you can assign to a variable is an object, including a function.

>>> def inc():
...     return x + 1

>>> type(inc)
<class 'function'>

Normally, Python creates a function object upon function definition, but we can also instantiate a function like other objects - by calling its class:

>>> Function = type(inc)
>>> another_inc = Function(inc.__code__, {'x': 2})
>>> another_inc()
3

The class Function takes two required arguments. First, a code object which is a data structure containing compiled bytecode. Second, a dictionary that is the global scope of the resulting function. Indeed, calling the original inc would raise an error since x is not defined, but another_inc works because its global scope does have x.

More generally, the global scope of a function is the module that contains it. Let’s confirm this with a function from a standard module:

>>> import re
>>> from re import match
>>> match.__globals__ is re.__dict__
True

A module is a simple object whose main purpose is to hold objects that belong to it - in other words, provide a namespace. It turns out that we can also dynamically instantiate a module:

>>> Module = type(re)
>>> mod = Module('another module')
>>> dir(mod)
['__doc__', '__loader__', '__name__', '__package__', '__spec__']

Finally, we change the global scope of our existing function to the new module:

>>> mod.x = 42
>>> another_inc.__globals__.update(mod.__dict__)
>>> another_inc()
43