Skip to content

Instantly share code, notes, and snippets.

@pankajp
Created December 8, 2018 17:37
Show Gist options
  • Save pankajp/4fb4857b80c159c56f05ab3ad874b757 to your computer and use it in GitHub Desktop.
Save pankajp/4fb4857b80c159c56f05ab3ad874b757 to your computer and use it in GitHub Desktop.
Python module level property and cached property decorator
from mod_prop import mod_property, cached_mod_property
@mod_property
def my_prop():
print('my_prop called')
return 42
@cached_mod_property
def my_cached_prop():
print('my_cached_property called')
return '24'
import caching_mod
print(caching_mod)
print('p', caching_mod.my_prop)
print('q', caching_mod.my_prop)
from caching_mod import my_prop
print('r', caching_mod.my_prop)
print('s', caching_mod.my_prop)
from caching_mod import my_cached_prop
print('t')
print('u', my_cached_prop)
print('v', caching_mod.my_cached_prop)
""" Module level property and cached property decorator """
import sys
import types
import functools
def update_module_class(mod):
class CachingModule(types.ModuleType):
pass
mod.__class__ = CachingModule
def mod_property(func, cached=False):
func_name = func.__name__
if '.' in func_name:
raise ValueError('mod_property only applicable to top-level module functions')
func_mod = sys.modules[func.__module__]
if func_mod.__class__ == types.ModuleType:
update_module_class(func_mod)
elif func_mod.__class__.__name__ != 'CachingModule':
raise RuntimeError(f'mod_property incompatible with module type: {func_mod.__name__}({func_mod.__class__.__qualname__})')
@functools.wraps(func)
def wrapper(mod):
value = func()
if cached:
setattr(func_mod.__class__, func_name, value)
delattr(func_mod, func_name)
return value
wrapper.__name__ = func_name
setattr(func_mod.__class__, func_name, property(wrapper))
return wrapper
def cached_mod_property(func):
return mod_property(func, cached=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment