I'm building a Python class that utilizes attribute chaining. I'm trying to figure out if there is a way to identify when the final attribute of a chain is called and execute some processing code at that point. After the final chained attribute is called, I'd like to process the collected data. I realize that a processing attribute could be called explicitly at the end of the chain, but I'd like to avoid that if possible.
For example:
o = ObjectInstance()
# Note that the attribute calling order is subjective
o('data').method_a('other data').method_c('other_data') #o.process() is called here automatically
--Update--
I've found a workaround that is specific to my situation, though it does not answer the underlying question.
For my particular case, I intend to process multiple chains separately with a single instance. By overriding the __call__
attribute of my class, I can check if the previous chain has been processed, and react accordingly. I was already planning to have a separate rendering method---which can also process the previous chain--after all chains were processed, so it works for my particular scenario.
The class would look something like:
class Chainable:
current_chain_data = None
processed_chains = list()
def __call__(self, data):
if self.current_chain_data:
self.process()
#Some logic
self.current_chain_data = data
return self
def method_a(self, data):
#Some logic
self.current_chain_data = data
return self
def method_b(self, data):
#...
def process(self, data):
#do stuff
self.processed_chains.append(self.current_chain_data)
self.current_chain_data = None
def render(self):
if self.current_chain_data:
self.process()
for c in self.processed_chains:
output += c
return output
And be used like:
c = Chainable()
# do some chaining
c('data').method_a('other_data').method_c('other_data')
# previous chain is processed here, new chain started
c('additional_data').method_b('other_data') #...
# previous chain is processed here, output rendered
c.render()
There is no way to recognise a "last" call, because a "chain" is not a language construct, but rather a consequnce of a uniform syntax combined with your own (good) practice of returning the same object from a non-functional method.
Your options are:
I would suggest option 1, unless option 2 naturally produces no performance penalty, if for no other reason than it introduces the least complexity, and explicit is usually better than implicit.
Your solution of overriding __call__
has several drawbacks: it is likely to confuse your users, because it is non-uniform; if someone calls another method on c
before calling c
, the behaviour might well surprise them (chain continued); and finally, you still need a final render
call to close out the last chain, which will make such code more fragile than necessary.