Python class method chaining

NFicano

To avoid getting lost in architectural decisions, I'll ask this with an analogous example:

lets say I wanted a Python class pattern like this:

queue = TaskQueue(broker_conn)
queue.region("DFW").task(fn, "some arg") 

The question here is how do I get a design a class such that certain methods can be "chained" in this fashion.

task() would require access to the queue class instance attributes and the operations of task depends on the output of region().

I see SQLalchemy does this (see below) but am having difficulty digging through their code and isolating this pattern.

query = db.query(Task).filter(Task.objectid==10100) 
Martijn Pieters

SQLAlchemy produces a clone on such calls, see Generative._generate() method which simply returns a clone of the current object.

On each generative method call (such as .filter(), .orderby(), etc.) a new clone is returned, with a specific aspect altered (such as the query tree expanded, etc.).

SQLAlchemy uses a @_generative decorator to mark methods that must operate and return a clone here, swapping out self for the produced clone.

Using this pattern in your own code is quite simple:

from functools import wraps

class GenerativeBase(object):
    def _generate(self):
        s = self.__class__.__new__(self.__class__)
        s.__dict__ = self.__dict__.copy()
        return s

def _generative(func):
    @wraps(func)
    def decorator(self, *args, **kw):
        new_self = self._generate()
        func(new_self, *args, **kw)
        return new_self
    return decorator


class TaskQueue(GenerativeBase):
    @_generative
    def region(self, reg_id):
        self.reg_id = reg_id

    @_generative
    def task(self, callable, *args, **kw):
        self.tasks.append((callable, args, kw))

Each call to .region() or .task() will now produce a clone, which the decorated method updates by altering the state. The clone is then returned, leaving the original instance object unchanged.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related