链接方法后调用属性

时间:2012-03-17 17:14:12

标签: python chaining

我正在构建一个利用属性链的Python类。我试图弄清楚是否有一种方法可以确定何时调用链的最终属性并在该点执行某些处理代码。在调用最终的链接属性之后,我想处理收集的数据。我意识到可以在链的末尾显式调用处理属性,但是如果可能的话我想避免这种情况。

例如:

o = ObjectInstance()
# Note that the attribute calling order is subjective
o('data').method_a('other data').method_c('other_data') #o.process() is called here automatically

- 更新 -

我找到了一种特定于我的情况的解决方法,但它没有回答基本问题。

对于我的特定情况,我打算用单个实例分别处理多个链。通过覆盖我的类的__call__属性,我可以检查前一个链是否已被处理,并做出相应的反应。我已经计划在处理完所有链之后,有一个单独的渲染方法---它也可以处理前一个链,因此它适用于我的特定场景。

该课程类似于:

class Chainable:

    current_chain_data = None
    processed_chains = list()


    def __call__(self, data):
        if self.current_chain_data:
            self.process()

        #Some logic
        self.current_chain_data = data
        return self


    def method_a(self, data):
        #Some logic
        self.current_chain_data = data
        return self

    def method_b(self, data):
        #...

    def process(self, data):
        #do stuff
        self.processed_chains.append(self.current_chain_data)
        self.current_chain_data = None

    def render(self):
        if self.current_chain_data:
            self.process()

        for c in self.processed_chains:
            output += c
        return output

可以像:

一样使用
c = Chainable()

# do some chaining
c('data').method_a('other_data').method_c('other_data')

# previous chain is processed here, new chain started
c('additional_data').method_b('other_data') #...

# previous chain is processed here, output rendered
c.render()

2 个答案:

答案 0 :(得分:1)

无法识别“最后”调用,因为“链”不是语言构造,而是统一语法的结果与您自己(好)从非返回相同对象的实践相结合功能方法。

您的选择是:

  1. 进行最后的流程调用,正如您所建议的那样(在许多方面是最干净的解决方案);
  2. 在每个阶段执行您的处理(可能会或可能不会影响性能,具体取决于处理,以及您的方法实际执行的操作);或
  3. 让每个方法定义一个关键字参数,允许您将其标记为最终调用,以便触发处理。
  4. 我建议选项1,除非选项2自然不产生性能损失,如果没有其他原因导致复杂性最小,而显式通常优于隐式。

    您的覆盖__call__的解决方案有几个缺点:它可能会让您的用户感到困惑,因为它不均匀;如果在调用c之前有人在c上调用了另一种方法,则行为可能会让他们感到惊讶(链接继续);最后,你仍然需要一个最后的render调用来关闭最后一个链,这将使这些代码比必要的更脆弱。

答案 1 :(得分:0)

class DataObject:

        def __init__(self, data):

                self.data = data


        def method_a(self, data):

                self.data += data

                return self


        def method_c(self, data):

                self.data += data

                return self

        def process(self):

                print self.data

if __name__ == "__main__":

        o = DataObject('data')
        o.method_a('other data').method_c('other_data').process()