关于装饰器:智能地按顺序执行Python函数

Intelligently Execute Python Functions in Order

我很好奇在程序中调用函数的相对优点是什么,使用一个修饰器来创建函数的有序映射,并遍历该映射,而不是直接按我想要的顺序调用函数。下面是两个产生相同结果的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
PROCESS_MAP = {}


def register(call_order):
    def decorator(process_func):
        PROCESS_MAP[call_order] = process_func
        return process_func
    return decorator


@register(99)
def func3():
    print 'last function'


@register(1)
def func0():
    print 'first function'


@register(50)
def func1():
    print 'middle function'


def main():
    for func in sorted(PROCESS_MAP):
        foo = PROCESS_MAP[func]
        foo()

if __name__ == '__main__':
    main()

印刷品:

1
2
3
first function
middle function
last function

这是否比执行以下操作更好?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def func2():
    print 'last function'


def func0():
    print 'first function'


def func1():
    print 'middle function'


def main():
    func0()
    func1()
    func2()

if __name__ == '__main__':
    main()

还有一些问题:

  • 更多的Python?
  • 比它的价值更多的工作?
  • 如果您没有正确分配订单,它是否会打开太多问题的大门?
  • 是否有更智能的设计来按正确的顺序调用函数?


在我能想到的所有情况下,我更喜欢第二种(非装饰)方法。显式地命名函数是直接的、明显的和清晰的。考虑问"这个函数是从哪里调用的?"以及在每种情况下你如何回答这个问题。

在您的装饰器中有一个可能的bug,它会悄悄地删除一个与另一个函数具有相同调用顺序号的函数。


第一个可以让您在需要时动态地更改顺序,还可以让您使用外部脚本更容易地更改顺序。

如果你的程序逻辑清晰而简单,或者如果你的程序有一天会变得更复杂,并且装饰器会变得不相关/需要进行重大的修改以适应-使用第二个。

您可以在这里了解更多常用的装饰:Python装饰器的一些常见用途是什么?

但最后,我想说,这真的取决于你的设计和程序的目的。此外,我建议,如果选择第一种方法,写一个更好的机制来记录顺序,处理两个函数等等。这些改进可能会使装饰师值得。


Peak Rules有一些有趣的实用程序,包括@before,@after decorators和一个有趣的系统,用于制定规则来强制执行某些行为。

一个更简单的机制是为每个函数分配一个"权重",然后按加权顺序对它们进行排序——尽管这假定一个函数数组。如果存在层次结构,可以对DAG进行拓扑排序,以获得节点的线性数组。


我说的是第二种方法,除非您不知何故想调用很多函数,而且太懒惰而无法键入(如果您确实这样做了,那么您的结构可能有问题)。它不仅可读性更强,从而有助于最小化不必要的错误,而且还更短。