为了避免迷失在建筑决策中,我会用一个类似的例子来问这个:
假设我想要一个像这样的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)
答案 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
进行更改。