Dot operator magic has me stymied...

Arnaud Delobelle arnodel at googlemail.com
Wed Oct 29 21:15:21 CET 2008


On Oct 29, 7:46 pm, "Casey Rodarmor" <caseyrodar... at gmail.com> wrote:
> Hi All,
>
> I'm trying to use a class as a decorator for another class method, but
> it's giving me a lot of grief. Basically, my problem is with the
> example below:
>
> >>> class decorator:
>
> ...     def __init__(self, function):
> ...         self.function = function
> ...
> ...     def __call__(self, *args, **kwargs):
> ...         self.function(*args, **kwargs)
> ...>>> class Foo:
>
> ...     def __init__(self):
> ...         self.msg = "Hello,"
> ...
> ...     @decorator
> ...     def greet(self, name):
> ...         print self.msg, name
> ...>>> foo = Foo()
> >>> foo.greet("Bob")
>
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "decorate.py", line 6, in __call__
>     self.function(*args, **kwargs)
> TypeError: greet() takes exactly 2 arguments (1 given)
>
> I'm guessing that using a decorator that returns a class instance
> instead of a function instance has messed up the magic of the dot
> operator, causing it not to bind the foo instance to the self
> argument.
>
> Can anybody shed some light on what's happening here?

When

    @decorator
    def greet(self, name):
        print self.msg, name

is executed, a new decorator object is created whose function
attribute is the function 'greet' above (with two arguments) and the
result is given the name 'greet'.

Later, when

>>> foo = Foo()
>>> foo.greet("Bob")

is executed,

foo.greet is a decorator object whose attribute 'function' is the
plain function 'greet'. So it expects two arguments and you only
provide one.

To fix this you could use the Descriptor protocol.  If you don't know
what it is, I suggest you read this:

    http://users.rcn.com/python/download/Descriptor.htm

It should give you what you need to get it right.

HTH

--
Arnaud





More information about the Python-list mailing list