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 -- https://mail.python.org/mailman/listinfo/python-list