So first of all, decorators are meant to be generic things which can be applied to a larger group of things. The decorators you came up with are extremely specific to your Fred
class to the point where it makes no sense to have them defined even outside of it (The name Fred
is even hardcoded into them).
What’s even worse, the decorators are very hacky, accessing locals()
, globals()
, and using eval
to execute dynamic code. None of that is a good idea. Also, the way you build upon the names of the function make the logic highly dependent on the public interface of the class—or the other way around, the public interface is highly dependent on the implementation details of your thing. get_name_names
is definitely not a good function name.
Next, I don’t even know what the purpose of this is. Overall, you seem to want some kind of lazy loading, as you get the data from elsewhere via REST. That’s fine, but doesn’t judge this kind of language abusing. The way you are hiding the actual lookup logic in those decorators makes it impossible to understand what’s going on, making maintenance extremely hard.
Instead, it would be more than fine if you just duplicated a bit inside the functions but had a clear and simple logic flow that way. It’s likely that the program will run faster that way too.
If you want to implement lazy-loading nicely, you could try properties. That could look like this:
import time
NAMES = [
{'name': 'Fred Flintstone', 'id': 1},
{'name': 'Barney Rubble', 'id': 2},
{'name': 'Henry Ford', 'id': 3}
]
class Fred (object):
def __init__ (self):
self._names = []
@property
def names (self):
if not self._names:
print('Load the data here; might take a while.')
time.sleep(5)
self._names = NAMES
return self._names
def getNames (self):
return [x['name'] for x in self.names]
def searchNameById (self, id):
return filter(lambda x: x['id'] == id, self.names)
def searchNameByName (self, name):
return filter(lambda x: x['name'] == name, self.names)
f = Fred()
print('Querying some stuff:')
print(f.searchNameById(2))
print(f.searchNameByName('Fred Flintstone'))
print(f.names)
print(f.getNames())
Executed, it yields this result. Note that the data is only loaded once:
Querying some stuff:
Load the data here; might take a while.
[{'name': 'Barney Rubble', 'id': 2}]
[{'name': 'Fred Flintstone', 'id': 1}]
[{'name': 'Fred Flintstone', 'id': 1}, {'name': 'Barney Rubble', 'id': 2}, {'name': 'Henry Ford', 'id': 3}]
['Fred Flintstone', 'Barney Rubble', 'Henry Ford']
And I’d argue that this is a lot clearer than your decorator stuff.