Python类方法链接

NFi*_*ano 12 python magic-methods python-2.7

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

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

queue = TaskQueue(broker_conn)
queue.region("DFW").task(fn, "some arg") 
Run Code Online (Sandbox Code Playgroud)

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

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

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

query = db.query(Task).filter(Task.objectid==10100) 
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 14

SQLAlchemy在这样的调用上生成一个克隆,请参阅只返回当前对象的克隆的Generative._generate()方法.

在(如每个生成方法调用.filter(),.orderby()等等)的新克隆返回,与改变的特定方面(如查询树扩展等).

SQLAlchemy使用@_generative装饰器来标记必须操作的方法并在此处返回克隆,并交换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))
Run Code Online (Sandbox Code Playgroud)

每次调用.region().task()将生成一个克隆,其中装饰方法通过更改状态进行更新.然后返回克隆,保持原始实例对象不变.


the*_*eye 6

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

def region(self, my_string):
    ...
    ...
    return self
Run Code Online (Sandbox Code Playgroud)

由于region返回具有该task功能的当前对象,现在可以进行链接.

注意:

正如@chepner 在评论部分中提到的那样,确保region对对象进行更改self.