Re: Proposal: reducing self.x=x; self.y=y; self.z=z boilerplate code
Available news archives: comp.lang.tcl - comp.lang.python - comp.security.firewalls - sci.crypt - comp.lang.php - comp.lang.javascript
Google
 
Web news.hping.org


comp.lang.python archive

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

From: <mcherm@gmail.com>
Date: Tue Jul 05 2005 - 20:50:07 CEST

Ralf W. Grosse-Kunstleve wrote:
> I often find myself writing::
>
> class grouping:
>
> def __init__(self, x, y, z):
> self.x = x
> self.y = y
> self.z = z
> # real code, finally
>
> This becomes a serious nuisance in complex applications with long
> argument lists

Yes... indeed it does. This is so common that there is a standard
idiom for handling it:

    def __init__(self, x, y, z):
        self.__dict__.update(locals())

sometimes with modifications to avoid setting self.self.

> Therefore I propose that Python includes
> built-in support for reducing the ``self.x=x`` clutter.

If all you were proposing was a built-in function to make this
particular
idiom clearer and more reliable, then I think I'd back such a feature
because the need is SO common. However, the suggestion you actually
make:

> def __init__(self, .x, .y, .z):
> # real code right here

is far too broad and introduces new syntax unnecessarily.

You yourself are using a helper function (although I belive it could
be done more easily than you did it):

> I am actually using a simple trick::
>
> adopt_init_args(self, locals())

To which you raise the following objections:

> - The solution doesn't come with Python -> everybody has to reinvent.

Good point. Particularly since people won't think of all the
special cases (eg: classes with __slots__ defined).

> - People are reluctant to use the trick since scripts become
> dependent on a non-standard feature.
> - It is difficult to remember which ``import`` to use for
> ``adopt_init_args`` (since everybody has a local version/variety).

If the implementation is only 3-4 lines long (and a simpler
implementation
can be), then is can simply be included inline with every script that
needs
to use it.

> - The ``adopt_init_args(self, locals())`` incantation is hard to
> remember and difficult to explain to new-comers.

A better name would help with this. The need for locals() is
unavoidable.
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.

> - Inside the ``__init__()`` method, the same object has two names,
> e.g. ``x`` and ``self.x``. This lead to subtle bugs a few times
> when I accidentally assigned to ``x`` instead of ``self.x`` or vice
> versa in the wrong place (the bugs are typically introduced while
> refactoring).

Hmm... I've never had that problem, myself.

> - 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!

> - Remember where Python comes from: it goes back to a teaching
> language, enabling mere mortals to embrace programming.
> ``adopt_init_args(self, locals())`` definitely doesn't live up
> to this heritage.

No, but "self.x = x" does. It's only when you have lots of variables
or very long names that this approach becomes unwieldy.

> My minimal proposal is to add an enhanced version of ``adopt_init_args()``
> as a standard Python built-in function (actual name secondary!)::

I'd alter the name and the implementation, but the basic idea seems
sound to me.

> However, there is another problem not mentioned before:
> It is cumbersome to disable adoption of selected variables.

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.

> 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.

. . .

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.

-- Michael Chermside
Received on Thu Sep 29 16:46:24 2005