A nestedmodule decorator (Re: Namespaces are one honking great idea)

Gregory Ewing greg.ewing at canterbury.ac.nz
Tue Jul 5 05:10:15 EDT 2016


Steven D'Aprano wrote:
> There's only so far I can go without support from the compiler.

It turns out one can go surprisingly far. Here's something I
cooked up that seems to meet almost all the requirements.
The only shortcoming I can think of is that a nestedmodule
inside another nestedmodule won't be able to see the names
in the outer nestedmodule directly (much like nested classes).

% python3 test_nestedmodule.py
0.7071067811865475

#------------------------------------------
#
#   test_nestedmodule.py
#
#------------------------------------------

from math import pi, sin
from nestedmodule import nestedmodule

def f(x):
     return x**2

@nestedmodule
def test():

     def g(x):
         return f(x) * pi

     def h(x):
         return sin(g(x))

y = test.h(0.5)
print(y)

#------------------------------------------
#
#   nestedmodule.py
#
#------------------------------------------

from types import CodeType, ModuleType

def hack_code(f):
     """Hack 'return locals()' onto the end of the bytecode of f."""
     code1 = f.__code__
     bytes1 = code1.co_code
     names1 = code1.co_names
     n = len(names1)
     names2 = names1 + ('locals',)
     bytes2 = bytes1[:-4] + bytes([116, n, 0, 131, 0, 0, 83])
     code2 = CodeType(code1.co_argcount, code1.co_kwonlyargcount, code1.co_nlocals,
         code1.co_stacksize, code1.co_flags, bytes2, code1.co_consts, names2,
         code1.co_varnames, code1.co_filename, code1.co_name, code1.co_firstlineno,
         code1.co_lnotab, code1.co_freevars, code1.co_cellvars)
     return code2

def nestedmodule(f):
     c = hack_code(f)
     l = eval(c, f.__globals__)
     m = ModuleType(f.__name__)
     m.__dict__.update(l)
     return m



More information about the Python-list mailing list