5

I have a decorator declared as a class:

class predicated(object):
    def __init__(self, fn):
        self.fn = fn
        self.fpred = lambda *args, **kwargs: True

    def predicate(self, predicate):
        self.fpred = predicate
        return self

    def validate(self, *args, **kwargs):
        return self.fpred(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if not self.validate(*args, **kwargs):
            raise PredicateNotMatchedError("predicate was not matched")
        return self.fn(*args, **kwargs)

... and when I use it to wrap a method in a class, calling that method does not seem to set the instance of the object as the first argument. While this behavior is not exactly unexpected, how would I go about getting self to be frozen when the method becomes an instance method?


Simplified example:

class test_decorator(object):
    def __init__(self, fn):
        self.fn = fn
    def __call__(self, *args, **kwargs):
        return self.fn(*args, **kwargs)

class Foo(object):
    @test_decorator
    def some_method(self):
        print(self)

Foo().some_method()

Expected instance of foo, instead get an error saying 0 arguments were passed.

  • +1 for "Simplified example" :) – Aleksi Torhamo Apr 11 '11 at 03:21
  • I'd guess it does that because `some_method` is no longer a function, but instead an object - instance of the `test_decorator` class - so it doesn't create a bound method out of it. I have no idea how to make the scenario work with a "decorator class" though.. – Aleksi Torhamo Apr 11 '11 at 03:26

1 Answers1

4

Figured it out - needed to define a __get__ method in order to create a MethodType binding like so:

def __get__(self, obj, objtype=None):
    return MethodType(self, obj, objtype)

which creates a MethodType object when invoking the method on an object that freezes the self argument.

  • [This](http://stackoverflow.com/questions/5469956/python-decorator-self-is-mixed-up) post talks about the descriptor protocol – Pakman May 25 '12 at 20:12