Dcortez
Dcortez

Reputation: 4238

Dependency decorator with no duplictates

In a code below i have written depends decorator which just takes as a parametr some functions and call them before calling decorated function. So when when i use this script i get on output:

using f
using g
using f
using h

But now there comes my question. How to do it not to duplicate dependencies? So when i use h(), f() will be called just once? I tried to remove duplicates form functs, but for example for h() it's containing wapper and f(). Should I collect them in other way?

class depends(object):
    functs = []
    def __init__(self, *f):
        self.functs = []
        for i in f:
            self.functs.append(i)

    def __call__(self, fun):
        def wrapper():
            for i in self.functs:
                i()

            return fun()
        return wrapper

def f():
    print 'using f'

@depends(f)
def g():
    print 'using g'

@depends(g, f)
def h():
    print 'using h'

h()

Upvotes: 2

Views: 947

Answers (3)

unutbu
unutbu

Reputation: 880607

Python already has something like this already built into its super calling mechanism. However, to take advantage of super, you have to turn your dependencies into base classes:

def depends(*deps):
    def deco(func):
        def __new__(self):
            super(Dependency, self).__new__(self)
            return func()
        Dependency = type('Dependency', deps, {'__new__': __new__})
        return Dependency
    return deco


@depends(object)
def f():
    print 'using f'


@depends(f)
def g():
    print 'using g'


@depends(g, f)
def h():
    print 'using h'

h()
# using f
# using g
# using h

Upvotes: 3

Ber
Ber

Reputation: 41873

You need to check wether any of the dependency function has been decorated in this way, and exclude their dependencies from the ones for the currently decorated function.

This check needs to be done recursively.

It becomes much more difficult if you also use other decorators.

I really wonder why and how this construct is used.

Upvotes: 0

piokuc
piokuc

Reputation: 26204

You need to remember processed dependencies globally, for example in a class variable, see depends.done here:

class depends(object):
    done = []
    def __init__(self, *f):
        self.functs = f

    def __call__(self, fun):
        def wrapper():
            for i in self.functs:
                if i not in depends.done:
                    i() 
                    depends.done.append(i)

            return fun()
        return wrapper

def f():
    print 'using f'

@depends(f)
def g():
    print 'using g'

@depends(g, f)
def h():
    print 'using h'

h()

Upvotes: 1

Related Questions