confusion with decorators

Jason Swails jason.swails at gmail.com
Thu Jan 31 14:25:59 CET 2013


On Thu, Jan 31, 2013 at 12:46 AM, Steven D'Aprano <
steve+comp.lang.python at pearwood.info> wrote:

> On Wed, 30 Jan 2013 19:34:03 -0500, Jason Swails wrote:
>
> > Hello,
> >
> > I was having some trouble understanding decorators and inheritance and
> > all that.  This is what I was trying to do:
> >
> > # untested
> > class A(object):
> >    def _protector_decorator(fcn):
> >       def newfcn(self, *args, **kwargs):
> >          return fcn(self, *args, **kwargs)
> >       return newfcn
>
> Well, that surely isn't going to work, because it always decorates the
> same function, the global "fcn".
>

I don't think this is right.  fcn is a passed function (at least if it acts
as a decorator) that is declared locally in the _protector_decorator scope.
 Since newfcn is bound in the same scope and fcn is not defined inside
newfcn, I'm pretty sure that newfcn will just grab the fcn passed into the
decorator.

The following code illustrates what I'm trying to say (I think):

test.py:
#!/usr/bin/env python

a = 3

print 'Global namespace:', a

def myfunc(a):
   def nested_func():
      print 'nested_func a is:', a, 'id(a) =', id(a)

   print 'passed a is:', a, 'id(a) = ', id(a)
   nested_func()

myfunc(10)

$ python test.py
Global namespace: 3
passed a is: 10 id(a) =  6416096
nested_func a is: 10 id(a) = 6416096

Likewise, newfcn will use the function bound to the passed argument to the
decorator.  This syntax appears to work in my 'real' program.


> You probably want to add an extra parameter to the newfcn definition:
>
> def newfcn(self, fcn, *args, **kwargs):
>

I don't think I want to do that, since fcn  will simply become the first
argument that I pass to the decorated myfunc(), and if it's not callable
I'll get a traceback.

Also, I trust you realise that this is a pointless decorator that doesn't
> do anything useful? It just adds an extra layer of indirection, without
> adding any functionality.
>

Naturally.  I tried to contrive the simplest example to demonstrate what I
wanted.  In retrospect I should've picked something functional instead.

> Am I correct here?  My workaround was to simply copy the method from
> > class A to class B, after which B._protector_decorator decorated the
> > methods in B.
>
> That's not a work-around, that's an anti-pattern.
>
> Why is B inheriting from A if you don't want it to be able to use A's
> methods? That's completely crazy, if you don't mind me saying so. If you
> don't want B to access A's methods, simply don't inherit from A.
>
> I really don't understand what you are trying to accomplish here.
>

Again, my example code is over-simplified.  A brief description of my class
is a list of 'patch' (diff) files with various attributes.  If I want
information from any of those files, I instantiate a Patch instance (and
cache it for later use if desired) and return any of the information I want
from that patch (like when it was created, who created it, what files will
be altered in the patch, etc.).

But a lot of these patches are stored online, so I wanted a new class (a
RemotePatchList) to handle lists of patches in an online repository.  I can
do many of the things with an online patch that I can with one stored
locally, but not everything, hence my desire to squash the methods I don't
want to support.

I'd imagine a much more sensible approach is to generate a base class that
implements all methods common to both and simply raises an exception in
those methods that aren't.  I agree it doesn't make much sense to inherit
from an object that has MORE functionality than you want.

However, my desire to use decorators was not to disable methods in one
class vs. another.  The _protector_decorator (a name borrowed from my
actual code), is designed to wrap a function call inside a try/except, to
account for specific exceptions I might raise inside.  One of my classes
deals with local file objects, and the other deals with remote file objects
via urllib.  Naturally, the latter has other exceptions that can be raised,
like HTTPError and the like.  So my desire was to override the decorator to
handle more types of exceptions, but leave the underlying methods intact
without duplicating them.

I can do this without decorators easily enough, but I thought the decorator
syntax was a bit more elegant and I saw an opportunity to learn more about
them.

Possibly Java.
>

I took a Java class in high school once ~10 years ago... haven't used it
since. :)  Truth be told, outside of Python, the languages I can work in
are Fortran (and to a much lesser extent), C and C++.

import functools
>

I need to support Python 2.4, and the docs suggest this is 2.5+.  Too bad,
too, since functools appears pretty useful.

Thanks for the help!
Jason
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20130131/96b56a47/attachment.html>


More information about the Python-list mailing list