Skip to content

Instantly share code, notes, and snippets.

@jcrist
Created August 30, 2015 20:47
Show Gist options
  • Save jcrist/39db5994c71511572846 to your computer and use it in GitHub Desktop.
Save jcrist/39db5994c71511572846 to your computer and use it in GitHub Desktop.
Parametric Modules and functors in Python
from types import ModuleType
import sys
import inspect
from contextlib import contextmanager
class LocalImportFinder(object):
def find_module(self, fullname, path=None):
if path:
return None
lk = inspect.stack()[1][0].f_locals
qual = lk.get(fullname, None)
if qual and isinstance(qual, ModuleType):
return LocalImportLoader(qual)
return None
class LocalImportLoader(object):
def __init__(self, mod):
self.mod = mod
def load_module(self, fullname):
return self.mod
@contextmanager
def local_imports():
"""Temporarily turn on local imports"""
finder = LocalImportFinder()
sys.meta_path.append(finder)
yield
sys.meta_path.remove(finder)
# An example functor to take a module, and return a new module with additional
# methods for adding each integer found in the module.
def summation_functor(mod):
m = ModuleType(mod.__name__, mod.__doc__)
m.__dict__.update(mod.__dict__)
for k, v in mod.__dict__.items():
if isinstance(v, int):
setattr(m, 'add_' + k, make_adder(v))
return m
# Needed due to how python handles closures
def make_adder(v):
return lambda x: x + v
# Create a module in this file. This would also work with an imported module.
foo = ModuleType('foo')
foo.a = 1
foo.b = 2
foo.c = 3
# Apply the functor to return a new module
foo_with_sum = summation_functor(foo)
# Import things from the module created in this file.
with local_imports():
from foo_with_sum import add_a, add_b, add_c
@jcrist
Copy link
Author

jcrist commented Aug 30, 2015

Note that the exact same behavior could have been accomplished by using objects, and the line

add_a, add_b, add_c = (getattr(foo_with_sum, i) for i in ('add_a', 'add_b', 'add_c'))

This is 100% just a syntax hack to get import syntax for objects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment