python中的方法链延迟执行

时间:2018-07-14 07:38:46

标签: python python-3.x lazy-evaluation method-chaining

我的TestClass对象的python程序中有一系列方法,如下所示:-

TestClass().method1(args).method2(args).method3(args)

我想构建一个实用程序,它将扫描上述链,然后可以构建执行序列。 (类似于数据处理框架构建其执行图或dag的方式)。另外,直到我最后调用run()时,上述序列才会运行。

因此,就我而言,它仅在将run()方法添加到链的末尾时才能运行。

TestClass().method1(args).method2(args).method3(args).run()

如何实现?

2 个答案:

答案 0 :(得分:3)

您想要的就像是一个流畅的界面。

我给你一个简单的例子,用某种装饰器肯定可以使它更好

class A:
    def __init__(self):
        self.call_chain = []

    def m1(self, arg):
        def _actual_logic():
            print(arg)
        self.call_chain.append(actual_logic)
        return self

    def run(self):
        for f in self.call_chain:
            f()

a = A().m1('snth')
a.run()

答案 1 :(得分:1)

这个answer的灵感来自于我的阐述。

因此,我将使用inspectre模块以及decorator来检查是否调用了run方法:

import re
import inspect

def check_run_is_called(func):
    def wrapper(*args, **kwargs):
        # Here the interesting part
        # We're searching if the string `.run()` exists in the code context
        run_exist = re.search(r'\.run\(.*?\)', inspect.stack()[-1].code_context[0])
        if not run_exist:
            raise Exception('Run must be called !')
        f = func(*args, **kwargs)
        return f
    return wrapper


class TestClass():
    @check_run_is_called
    def method1(self, arg):
        print(arg)
        return self

    @check_run_is_called
    def method2(self, arg):
        print(arg)
        return self

    @check_run_is_called
    def method3(self, arg):
        print(arg)
        return self

    def run(self):
        print('Run')


# test
if __name__ == '__main__':
    app = TestClass()
    app.method1('method1').method2('method2').method3('method3').run()

输出:

method1
method2
method3
Run

否则,如果我们在不包含run方法的情况下调用方法链:

app.method1('method1').method2('method2').method3('method3')

我们会得到一个Exception

Exception: Run must be called !

除此之外,您还可以像以下示例一样创建链的组合:

app.method1('method1').run()
# method1
# Run
app.method1('method1').method2('method2').run()
# method1
# method2
# Run
app.method2('method2').method3('method3').method1('method1').run()
# method2
# method3
# method1
# Run