Class decorator with argument

Chris Rebert clp2 at rebertia.com
Fri Jan 16 21:35:34 CET 2009


On Fri, Jan 16, 2009 at 12:15 PM, mk <mrkafk at gmail.com> wrote:
> Hello,
>
> I wrote this class decorator with argument:
>
>>>> class ChangeDoc(object):
>        def __init__(self, docstring):
>                self.docstring = docstring
>        def __call__(self, func):
>                func.__doc__ = self.docstring
>                return func
>
> It seems to work:
>
>>>> @ChangeDoc("bulba")
> def f():
>        pass
>
>>>> f.__doc__
> 'bulba'
>
> Can someone please debug my reasoning if it's incorrect?
>
> 1. First, the decorator @ChangeDoc('bulba') instantiates with __init__(self,
> 'bulba'), to some class instance, let's call it _decor.
>
> 2. Then _decor's __call__ method is called with function f as argument,
> changing the docstring and returning the changed f object, like f =
> _decor(f) .

Your reasoning is correct.

>
> Am I missing smth important / potentially useful in typical real-world
> applications in that picture?

You understand how it works, but apparently don't see its practical usefulness.
Consider, for the sake of example, some class whose methods all must
check that the provided login information is correct before performing
their operation. Without decorators, the login-checking code would get
repeated in every method. But we can avoid this by using decorators:

def requires_login(meth):
    def replacement(self, username, password, *args, **kwargs):
        if not login_valid(username, password):
            raise ValueError("Incorrect login")
        return meth(self, *args, *kwargs)
    return replacement

class RemoteAccount(object):
    @requires_login
    def show_file(self, filename):
        #implementation here...

    @requires_login
    def list_directory(self, dirname):
        #implementation here...


Notice how we were able to eliminate the username and password
parameter declarations and the 2 lines of irrelevant (from the POV of
the individual methods) login-checking code from every method and put
them in the decorator instead. All those saved lines add up to make
the code more readable.
Obviously this example is contrived, but it shows how decorators can
help you to address cross-cutting concerns in Python. In practice,
functions might have multiple, more complicated decorators applied to
them, thus increasing the gain from using decorators.

Cheers,
Chris

-- 
Follow the path of the Iguana...
http://rebertia.com



More information about the Python-list mailing list