I have a class with a large number of methods, the majority of which require that a single method is run first to populate a list in the class. However I'd also like to use lazy loading so that I can create instances without the initial load, until a method is called which requires the heavy loading. Therefore, I'd like to create a class where all methods are assumed to require the running of a given method, unless the method is selectively excluded. Here's my pseudo-code:
@all_methods_run_load
class myClass
things = []
params = []
@dont_run_load
def __init__(self, params):
self.params = params
@dont_run_load
def load(self):
self.things = do_a_ton_stuff()
def get_things():
return self.things
def get_some_things():
return apply_a_filter(self.things)
def get_first_thing():
return self.things[0]
def get_last_thing():
return self.things[-1]
Hopefully that makes sense. I'm pretty new to decorators themselves and still memorizing them, so I'm afraid the answer might blow my mind, however the thought crossed my mind and I can't help but investigate further :)
Although Aidan Kane is probably correct that you shouldn't be doing things this way, a solution to your stated problem could be phrased like so:
Here's the function that can decorate the methods.
import functools
def run_load(function):
"""Make a function run the class' load method before running."""
@functools.wraps(function)
def inner(self, *args, **kwargs):
self.load()
return function(self, *args, **kwargs)
return inner
Functions are mutable so you can just tag them.
def without_load(function):
"""Tag a method so that it shouldn't be decorated to call self.load."""
function.without_load = True
return function
You can decorate the class by just going through its members and setattr-ing them (found here).
import inspect
def decorate_all_with(decorator, predicate=None):
"""Apply a decorator to all methods that satisfy a predicate, if given."""
if predicate is None:
predicate = lambda _: True
def decorate_all(cls):
for name, method in inspect.getmembers(cls, inspect.isfunction):
if predicate(method):
setattr(cls, name, decorator(method))
return cls
return decorate_all
And that's it!
def should_be_loaded(function):
try:
return not bool(function.without_load)
except AttributeError:
return True
@decorate_all_with(run_load, should_be_loaded)
class MyClass:
things = []
params = []
@without_load
def __init__(self, params):
self.params = params
@without_load
def load(self):
self.things = do_a_ton_stuff()
def get_things(self):
return self.things
def get_some_things(self):
return apply_a_filter(self.things)
def get_first_thing(self):
return self.things[0]
def get_last_thing(self):
return self.things[-1]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With