Confusion about decorators

Arnaud Delobelle arnodel at gmail.com
Mon Dec 12 08:45:20 EST 2011


On 12 December 2011 13:27, Henrik Faber <hfaber at invalid.net> wrote:
> Hi group,
>
> I'm a bit confused regarding decorators. Recently started playing with
> them with Python3 and wanted (as an excercise) to implement a simple
> type checker first: I know there are lots of them out there, this is
> actually one of the reasons I chose that particular function (to compare
> my solution against other, proven solutions).
>
> Starting with a blank slate, I did something along the lines of:
>
> class _TypeCheckedFunction():
>        def __init__(self, decoratedfunction):
>                self._decoratedfunction = decoratedfunction
>
>        def __call__(self, *args, **kwargs):
>                [...] Actual checking
>
> def typecheck(wrappedfunction):
>        checkfunction = _TypeCheckedFunction(wrappedfunction)
>        functools.update_wrapper(checkfunction, wrappedfunction)
>        return checkfunction
>
> And decorate my methods like
>
>        @typecheck
>        def setbar(self, bar: str):
>
> This works somewhat. The problem is, however, when the method is
> actually called. This is what happens:
>
> 1. The decorator is called upon import of the decorated class. It
> creates a _TypeCheckedFunction(setbar) object.
> 2. When setbar is actually called (blubb.setbar("fooobar")), the
> __call__ method of the previously created _TypeCheckedFunction is invoked.
> 3. When trying to call self._decoratedfunction from within that object,
> this fails: "self" is missing! self._decoratedfunction is only the
> *function*, not the bound function of the object that contains setbar().
> Therefore I cannot proceed here.
>
> Solutions that I have seen working usually consist of two functions
> wrapped in each other, but I do not know why the additional introduction
> of a class makes everything fail.
>
> Can someone please enlighten me?

You can (need to?) use the descriptor protocol to deal with methods.

from functools import partial

class _TypeCheckedFunction():
       def __init__(self, decoratedfunction):
               self._decoratedfunction = decoratedfunction

       def __call__(self, *args, **kwargs):
               [...] Actual checking

       def __get__(self, obj, objtype):
               return partial(self, obj)

(Untested)

HTH

-- 
Arnaud



More information about the Python-list mailing list