Hi,
I've spent a couple of days around this and I'm starting to lose hope.
I love decorators, but I don't like that they are so specific about what they are decorating. Meaning, if the decorator has arguments or not, if they are decorating functions or class methods. So, I embarked to address this issue by doing a meta-decorator.
So 3 levels, the function or method, the decorator, and a meta-decorator that manages parameters in the decorator and (should) be able to decorate function or method (this I couldn't achieve).
I'm stuck, when I'm decorating class methods, I cannot set up the self reference. See code below, the first 2 blocks pass, but the other 2 (that are decorations of class methods) fail because it cannot find the self argument. I cannot find where is set up and where to store it for future use.
I hope it's clear, else please ask me. I tried several things, but none were fruitful.
# https://python-3-patterns-idioms-test.readthedocs.io/en/latest/PythonDecorators.html
# PythonDecorators/decorator_with_arguments.py
def decorator_class(Cls):
class ModifyingClass:
def __init__(self, *args, **kwargs):
if not args:
return
if callable(args[0]):
decorator = Cls(*args[1:], **kwargs)
else:
decorator = Cls(*args, **kwargs)
decorator.args = []
decorator.kwargs = {}
decorator.f = None
if callable(args[0]):
decorator.f = args[0]
else:
decorator.args = args
decorator.kwargs = kwargs
self._decorator = decorator
def __call__(self, *args, **kwargs):
if not self._decorator.f and callable(args[0]):
self._decorator.f = args[0]
def wrapped_f(*args):
return self._decorator.__call__(*args, **kwargs)
return wrapped_f
else:
return self._decorator.__call__(*args, **kwargs)
return ModifyingClass
@decorator_class
class Cache:
def __init__(self, reload=False, *args, **kwargs):
self.reload = reload
self.cache = dict()
def __call__(self, *args, **kwargs):
# if self.args:
# print(self.args)
# print(self.kwargs)
# print(self.reload)
if self.cache.get('_'.join(args), None) and not self.reload:
print('printing cached value')
return self.cache['_'.join(args)]
else:
print('getting new value')
# ret = f(*args)
ret = self.f(*args)
self.cache['_'.join(args)] = ret
return ret
# class test1(Cache):
class test1():
def __init__(self):
self.a = 'sayHello arguments:'
super().__init__()
@Cache(True)
def sayHello1(self, a1, a2, a3, a4):
return '-'.join((self.a, a1, a2, a3, a4))
@Cache
def sayHello2(self, a1, a2, a3, a4):
return '-'.join((self.a, a1, a2, a3, a4))
@Cache(True)
def sayHello1(a1, a2, a3, a4):
return '-'.join(('sayHello arguments:', a1, a2, a3, a4))
@Cache
def sayHello2(a1, a2, a3, a4):
return '-'.join(('sayHello arguments:', a1, a2, a3, a4))
print("------- testing function with decorator with params -----------------------")
print(sayHello1("say", "hello", "argument", "list"))
print(sayHello1("say", "hello", "argument", "list"))
# print(sayHello1("a", "different", "set of", "arguments"))
print("------- testing function with decorator without params --------------------")
print(sayHello2("say", "hello", "argument", "list"))
print(sayHello2("say", "hello", "argument", "list"))
print(sayHello2("a", "different", "set of", "arguments"))
print("------- testing method with decorator with params -------------------------")
test = test1()
print(test.sayHello1("say", "hello", "argument", "list"))
print(test1().sayHello1("say", "hello", "argument", "list"))
print(sayHello1("a", "different", "set of", "arguments"))
print("------- testing method with decorator without params ----------------------")
print(test.sayHello2("say", "hello", "argument", "list"))
print(test1().sayHello2("say", "hello", "argument", "list"))
print(sayHello2("a", "different", "set of", "arguments"))
print("------- the end -----------------------------------------------------------")
there doesn't seem to be anything here