David542
David542

Reputation: 110093

Method chaining in python and how to have access to the entire string

I would like to add a basic class that does some method chaining in a sql/pandas-like way. Something like:

ResultSet.filter(...).exclude(...).sort(...)

I've done some methods like this before and it's pretty straightforward, as I'll just return self at the end.

However, I want to also be able to introspect the entire method-chaining-sequence as occasionally I will have to do things differently if a following/preceding method performs a certain action. So basically, I want to have access to the entire "ResultSet.filter(...).exclude(...).sort(...)" as a string saved somewhere.

It's almost like I would need a prepare method that stores the string of the entire 'statement' and then the actual execution methods filter, exclude, etc. Perhaps the easiest way might just be to add in an .execute() or .commit() method at the end which builds the context and then evaluates everything.

How could this be done?

Upvotes: 1

Views: 208

Answers (1)

Jerry101
Jerry101

Reputation: 13357

This approach logs the operations:

class ResultSet:
  def __init__(self):
    self.operation_sequence = []

  def filter(self, *args):
    self.operation_sequence.append(('filter', args))
    ... filter work ...
    return self

  def exclude(self, *args):
    self.operation_sequence.append(('exclude', args))
    ... exclude work ...
    return self

  def sort(self, *args):
    self.operation_sequence.append(('sort', args))
    ... sort work ...
    return self

  @property
  def sequence(self):
    return self.operation_sequence  # reformat the data as desired

This approach accumulates deferred operations until the execute() method gets called:

class ResultSet:
  def __init__(self):
    self.operation_sequence = []

  def filter(self, *args):
    self.operation_sequence.append(('filter', args))
    return self

  def exclude(self, *args):
    self.operation_sequence.append(('exclude', args))
    return self

  def sort(self, *args):
    self.operation_sequence.append(('sort', args))
    return self

  def execute(self):
    ## TODO: Process the interdependencies then run the operations.
    self.operation_sequence = []

If there are many self-logging operations, I'd implement the logging via a decorator or even a metaprogramming technique on method calls.

Upvotes: 1

Related Questions