问题描述
为了避免迷失在架构决策中,我会用一个类似的例子来问这个问题:
To avoid getting lost in architectural decisions, I'll ask this with an analogous example:
假设我想要一个这样的 Python 类模式:
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()
需要访问 queue
类实例属性,task
的操作依赖于 region 的输出()
.
task()
would require access to the queue
class instance attributes and the operations of task
depends on the output of region()
.
我看到 SQLalchemy 这样做(见下文),但我很难深入挖掘他们的代码并隔离这种模式.
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)
推荐答案
SQLAlchemy 对此类调用生成克隆,请参阅 Generative._generate()
方法,它只返回当前对象的克隆.
SQLAlchemy produces a clone on such calls, see Generative._generate()
method which simply returns a clone of the current object.
在每次生成方法调用(例如 .filter()
、.orderby()
等)时,都会返回一个新的克隆,并更改了特定方面(例如展开的查询树等).
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 使用 装饰器 标记必须操作的方法,并在此处返回一个克隆,将
self
替换为生成的克隆.
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))
对 .region()
或 .task()
的每次调用现在都会产生一个克隆,装饰方法通过改变状态来更新它.然后返回克隆,保持原始实例对象不变.
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.
这篇关于Python 类方法链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!