Reputation: 7844
I am using cachetools for some basic caching. Here is an example of how I am using it:
class Access:
@cached(cache=TTLCache(maxsize=5, ttl=10))
def get_some_value(input: str):
# do some calls and return a value
The problem here is how do I make the maxsize
and ttl
configurable? I cannot do something like
class Access:
def __init__(self, maxsize: int = 5, ttl: int = 10):
self.maxsize = maxsize
self.ttl = ttl
@cached(cache=TTLCache(maxsize=self.maxsize, ttl=self.ttl))
def get_some_value(input: str):
# do some calls and return a value
I am looking for a way to inject those values if required and also have a default. Any helpful pointers?
Also, get_some_value()
need not be an instance method. I could just make it a class method or module level also if need be.
Upvotes: 1
Views: 565
Reputation: 51093
This can't work using the regular decorator syntax, for two reasons: get_some_value
belongs to the class, so it cannot have different behaviour for different instances since there's only one "copy" of it; and the decorator is executed at the time of the class declaration, not at the time of the instance creation, so there are no __init__
arguments yet.
However, you can get the result you want by applying the decorator explicitly in the __init__
method:
class Access:
def __init__(self, maxsize: int = 5, ttl: int = 10):
decorator = cached(cache=TTLCache(maxsize=maxsize, ttl=ttl))
self.get_some_value = decorator(self.get_some_value)
def get_some_value(self, input: str):
...
Upvotes: 2
Reputation: 2331
To deal with this, we can use the fact that Python decorators are simply functions that return other functions.
Suppose you have this eggs
decorator:
def eggs(foo=10, bar=20):
def wrapper_gen(func):
def wrapper(*args):
print(foo, bar)
func(*args)
return wrapper
return wrapper_gen
And this Spam
class:
class Spam:
@eggs(foo=10, bar=20)
def baz(self, input):
print(input)
We can call the baz
method as such:
Spam().baz("Hello, world!")
And this gives us
10 20
Hello, world!
Now, instead of directly decorating the function, we'll decorate in our __init__
method:
class Spam:
def __init__(self, foo=10, bar=20):
self.baz = eggs(foo=foo, bar=bar)(self._baz_func)
def _baz_func(self, input):
print(input)
And now:
Spam(foo=20, bar=30).baz("Hello, world!")
This outputs
20 30
Hello, world!
The reason this works is that this:
@foo
def bar():
...
is shorthand for this:
def bar():
...
bar = foo(bar)
Upvotes: 2