Created
December 8, 2018 17:37
-
-
Save pankajp/4fb4857b80c159c56f05ab3ad874b757 to your computer and use it in GitHub Desktop.
Python module level property and cached property decorator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" 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