0

I'm curious what the relative merits are of calling functions in a program using a decorator to create an ordered map of the functions, and iterating through that map, versus directly calling the functions in the order I want. Below are two examples that yield the same result:

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()

This prints:

first function
middle function
last function

Is this any better than doing the following?

def func2():
    print 'last function'


def func0():
    print 'first function'


def func1():
    print 'middle function'


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

if __name__ == '__main__':
    main()

Some more questions:

  • More Pythonic?
  • More work than it's worth?
  • Does it open the door to too many issues if you don't properly assign the order correctly?
  • Are there more intelligent designs for calling functions in the right order?
  • That's a pretty clever way of using decorators, but I think it makes your program logic harder to follow. – TheSoundDefense Aug 04 '14 at 20:40
  • 4
    If the functions must always be called together in the same order that suggests that they act like one long function. – Jason S Aug 04 '14 at 20:43

4 Answers4

4

I would prefer the second (non-decorated) approach in all situations I can think of. Explicitly naming the functions is direct, obvious, and clear. Consider asking the question "where is this function called from?" and how you might answer that in each case.

There is a possible bug in your decorator where it would silently drop a function that has the same call order number as a different function.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • If you wand to adjust functions order upon a parameter or if you often change the order and you want to use a script, the first one does give you an advantage – Acsisr Aug 04 '14 at 21:05
1

The first one will let you change order dynamically if you need and will also let you change the order with an external script much easier.

If your program's logic is clear and simple OR if you program will one day become more complex and the decorator will be irrelevant/will need to go under major changes in order to fit- use the second one.

You can read about more of the decorations common uses here: What are some common uses for Python decorators?

But to conclude, I would say it really depends on your design and what is the programs purpose. Furthermore, I would suggest, if choosing the first way, writing a better mechanism that will log the order, handle two function and more. Those improvements will maybe make the decorator worth it.

Community
  • 1
  • 1
Acsisr
  • 186
  • 1
  • 15
0

I say the second approach, unless you somehow wants to call a lot of functions and too lazy to type (and if you're actually doing this, there might be something wrong with your structure). Not only it is more readable and thus help minimize unnecessary errors, but it's also shorter.

Truerror
  • 146
  • 4
0

PEAK Rules has some interesting utilities for this with @before, @after decorators and an interesting system for making rules to enforce certain behaviors.

A simpler mechanism would be to assign a 'weight' to each function and then sort them in weighted order - although this assumes a single array of functions. You can do a topological sort on a DAG to get a linear array of nodes if there is a hierarchy.

synthesizerpatel
  • 27,321
  • 5
  • 74
  • 91