Last active
October 6, 2023 13:05
-
-
Save odigity/53151ffad127966ce3cf28b23be96f44 to your computer and use it in GitHub Desktop.
Funktools - cobbling together a superset of Python's functools
This file contains hidden or 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
A collection of Python functools-inspired extensions from other sources. |
This file contains hidden or 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 random import randint | |
from funktools import module_property, cached_module_property | |
@module_property | |
def my_module_property(): | |
print("my_module_property()") | |
@cached_module_property | |
def my_cached_module_property(): | |
result = randint(100,999) | |
print(f"my_cached_module_property() -> {result}") | |
return result |
This file contains hidden or 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 random import randint | |
from funktools import class_property, cached_class_property, cache, cached_property | |
import bar | |
def my_function(): | |
print("my_function()") | |
@cache | |
def my_cached_function(): | |
result = randint(100,999) | |
print(f"my_cached_function() -> {result}") | |
return result | |
class MyClass: | |
## Static Method | |
@staticmethod | |
def my_static_method(): | |
print("my_static_method()") | |
## Class Method | |
@classmethod | |
def my_class_method(cls): | |
print(f"my_class_method({cls})") | |
## Class Property | |
@class_property | |
def my_class_property(cls): | |
print(f"my_class_property({cls})") | |
## Cached Class Property | |
@cached_class_property | |
def my_cached_class_property(cls): | |
result = randint(100,999) | |
print(f"my_cached_class_property({cls}) -> {result}") | |
return result | |
## Instance Method | |
def my_instance_method(self): | |
print(f"my_instance_method({self})") | |
## Instance Property | |
@property | |
def my_instance_property(self): | |
print(f"my_instance_property({self})") | |
## Cached Instance Property | |
@cached_property | |
def my_cached_instance_property(self): | |
result = randint(100,999) | |
print(f"my_cached_instance_property({self}) -> {result}") | |
return result | |
my_function() | |
my_cached_function() | |
my_cached_function() | |
bar.my_module_property | |
bar.my_cached_module_property | |
bar.my_cached_module_property | |
MyClass.my_static_method() | |
MyClass.my_class_method() | |
MyClass.my_class_property | |
MyClass.my_cached_class_property | |
MyClass.my_cached_class_property | |
a = MyClass() | |
a.my_instance_method() | |
a.my_instance_property | |
a.my_cached_instance_property | |
a.my_cached_instance_property |
This file contains hidden or 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 sys | |
import types | |
from functools import cache, cached_property, wraps # noqa (for re-export) | |
## Copied from: https://gist.github.com/pankajp/4fb4857b80c159c56f05ab3ad874b757 | |
def _update_module_class(mod): | |
class CachingModule(types.ModuleType): | |
pass | |
mod.__class__ = CachingModule | |
def module_property(func, cached=False): | |
func_name = func.__name__ | |
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__})') | |
@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_module_property(func): | |
return module_property(func, cached=True) | |
## Copied from: https://github.com/dssg/dickens/blob/2.0.0/src/descriptors.py | |
class class_property: | |
"""Descriptor decorator implementing a class-level read-only property.""" | |
def __init__(self, func): | |
self.__func__ = func | |
def __get__(self, instance, cls=None): | |
if cls is None: | |
cls = type(instance) | |
return self.__func__(cls) | |
class cached_class_property: | |
"""Descriptor decorator implementing a class-level, read-only property, | |
which caches its results on the class(es) on which it operates. | |
Inheritance is supported, insofar as the descriptor is never hidden by its cache; | |
rather, it stores values under its access name with added underscores. For example, | |
when wrapping getters named "choices", "choices_" or "_choices", each class's result | |
is stored on the class at "_choices_"; decoration of a getter named "_choices_" | |
would raise an exception.""" | |
class AliasConflict(ValueError): | |
pass | |
def __init__(self, func): | |
self.__func__ = func | |
self.__cache_name__ = '_{}_'.format(func.__name__.strip('_')) | |
if self.__cache_name__ == func.__name__: | |
raise self.AliasConflict(self.__cache_name__) | |
def __get__(self, instance, cls=None): | |
if cls is None: | |
cls = type(instance) | |
try: | |
return vars(cls)[self.__cache_name__] | |
except KeyError: | |
result = self.__func__(cls) | |
setattr(cls, self.__cache_name__, result) | |
return result |
This file contains hidden or 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
my_function() | |
my_cached_function() -> 480 | |
my_module_property() | |
my_cached_module_property() -> 300 | |
my_static_method() | |
my_class_method(<class '__main__.MyClass'>) | |
my_class_property(<class '__main__.MyClass'>) | |
my_cached_class_property(<class '__main__.MyClass'>) -> 681 | |
my_instance_method(<__main__.MyClass object at 0x7f3d49fbda90>) | |
my_instance_property(<__main__.MyClass object at 0x7f3d49fbda90>) | |
my_cached_instance_property(<__main__.MyClass object at 0x7f3d49fbda90>) -> 592 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment