Python类方法链接

时间:2014-02-14 17:23:57

标签: python python-2.7 magic-methods

为了避免迷失在建筑决策中,我会用一个类似的例子来问这个:

假设我想要一个像这样的Python类模式:

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

这里的问题是如何让设计成为一个类,以便某些方法可以被链接"以这种方式。

task()需要访问queue类实例属性,task的操作取决于region()的输出。

我看到SQLalchemy这样做(见下文),但我很难深入挖掘他们的代码并隔离这种模式。

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

2 个答案:

答案 0 :(得分:14)

SQLAlchemy在此类调用上生成一个克隆,请参阅Generative._generate() method,它只返回当前对象的克隆。

在每个生成方法调用(例如.filter().orderby()等)上,返回一个新的克隆,并更改特定的方面(例如扩展的查询树等)。 / p>

SQLAlchemy使用@_generative decorator标记必须操作的方法并在此处返回克隆,为生成的克隆交换self

在您自己的代码中使用此模式非常简单:

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))

.region().task()的每次调用现在都会生成一个克隆,通过更改状态来更新装饰方法。然后返回克隆,保持原始实例对象不变。

答案 1 :(得分:6)

只需从region方法返回当前对象,就像这样

def region(self, my_string):
    ...
    ...
    return self

由于region返回具有task函数的当前对象,因此现在可以进行链接。

注意:

作为@chepner mentioned in the comments section,请确保region对对象self进行更改。