Proposal: reducing self.x=x; self.y=y; self.z=z boilerplate code

Ralf W. Grosse-Kunstleve rwgk at yahoo.com
Tue Jul 5 19:21:01 EDT 2005


Hi Michael,

Thanks for taking a careful look, and thanks for the balanced analysis!

Michael Chermside wrote:
> A better name would help with this.

OK. After getting so many beatings I'd agree to anything. :)

> The need for locals() is unavoidable.

It is in fact not unavoidable. I pointed to my prototype before,
but sorry, it is probably confusing that my two prototypes have the
same name. They just live in different modules. For easier access I
inline the second version that works without having to write "locals()"
(from libtbx.introspection):

  def frame_object(frames_back=0):
    try: raise Exception
    except:
      t = sys.exc_info()[2]
      f = t.tb_frame
      for i in xrange(frames_back+1):
        if (f.f_back is None): break
        f = f.f_back
      return f
  
  def adopt_init_args(exclusions=[], prefix="", frames_back=0):
    frame = frame_object(frames_back=frames_back+1)
    varnames = frame.f_code.co_varnames
    exclusions.append(varnames[0]) # self
    init_locals = frame.f_locals
    self = init_locals[varnames[0]]
    for varname in varnames:
      if (varname not in exclusions):
        setattr(self, prefix+varname, init_locals[varname])
    if ("__init__varnames__" not in exclusions):
      setattr(self, "__init__varnames__", varnames)

I am sure this can be improved and stripped down to the essentials.
E.g. I wasn't aware of sys._getframe() as just pointed out by Thomas
Heller (thanks!). To me this just shows that finding the optimal
solution is not entirely trivial and should therefore be done "right"
once and forever in a community effort. Ultimately I hope it will be
done in C for speed. That's the main goal of my proposal.

> But for REAL beginners, I wouldn't even bother... writing out "self.x = x"
> is useful for beginners since it helps make it very clear and concrete to
> them just what is happening.

In my experience real Python beginners grow very skeptical when I
make them type highly redundant code. Many are just waiting for
excuses not to learn Python and to continue with whatever they know
(in my field FORTRAN!). Even

  class point:

    def __init__(self, x, y):
      self.x = x
      self.y = y

makes for wrinkled noses. If I didn't use my home-grown
adopt_init_args() function in the real-world code pointed out earlier
the FORTRAN faction probably wouldn't stop making fun of me ("Why
doesn't he use COMMON blocks?").

> >   - In some cases the ``adopt_init_args()`` overhead was found to
> >     introduce a significant performance penalty (in particular the
> >     enhanced version discussed below).
> 
> Again... a different code will help here. And if execution speed is
> REALLY a concern, then you can just write it out the long way!

Why should anyone have to think about technicalities like this?
If we had an efficient C version included with Python nobody would
have to. One solution works for everything.

> The VERY simple, VERY straightforward, VERY common behavior of
> "store all the arguments as like-named attributes of self" is
> worth having a standard idiom (and *perhaps* a built-in). But
> odd special cases like skipping some arguments... that calls
> for writing the whole thing out. I'm firmly -1 on any proposal
> to support skipping arguments.

OK. "del x" is almost as good. I was motivated by speed concerns
(first adding x to self.__dict__, then removing it again), but it is
most likely a very minor issue, and my prototype with the repeated
list lookup may even backfire anyway.

> > When ``__slots__`` are used (cool feature!) the boilerplate problem
> > becomes even worse::
> >
> >   class grouping:
> >
> >       __slots__ = ["keep_this", "and_this", "but_this_again"]
> >
> >       def __init__(self, keep_this, and_this, but_not_this,
but_this_again):
> >           self.keep_this = keep_this
> >           self.and_this = and_this
> >           self.but_this_again = but_this_again
> >           # real code, finally
> >
> > Each variable name appears four times!
> 
> ** NO! **
> 
> __slots__ is *NOT* to be used except for those times when you NEED
> the performance advantages (mostly memory use). The simple rule is
> that you should *NEVER* use __slots__ (if you are in a situation
> where you *do* need it, then you'll know enough to understand why
> this advice doesn't apply to you). There should NOT be any support
> for auto-setting __slots__ *anywhere* in the standard library,
> because it would make it FAR too tempting for people to mis-use
> __slots__.
> 
> Besides, a metaclass would be a better solution, and it can be done
> today with no modifications to Python.

I am very puzzled to see the huge ** NO! **. If __slots__ improve
performance and reduce memory, what is wrong with using this feature?
I clearly was in situations where I needed __slots__, but I still
don't know what the dangers could be. Could you please explain
a little more?

> All in all, I think there's SOME merit to this idea, in that this
> is a common enough practice that it might be nice to make it easy
> to type (and read). But your proposal entangles the good idea with
> several ideas I rather dislike, and on the whole I think it sounds
> rather dangerous.

I am OK to strip down the proposal to concentrate solely on an
optimal, fast, C-coded built-in function. That alone would be a major
step forward, with a life-changing potential similar to that of zip,
enumerate, or inplace operators (+=, *=, etc.). (I guess I am showing
my age.)

I was also considering working in Josiah Carlson's metaclass solution
(http://mail.python.org/pipermail/python-list/2005-July/288349.html)
to the __slots__ problem, but after reading your message I am not so
sure anymore...

Cheers,
        Ralf



		
____________________________________________________ 
Yahoo! Sports 
Rekindle the Rivalries. Sign up for Fantasy Football 
http://football.fantasysports.yahoo.com



More information about the Python-list mailing list