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

mcherm at gmail.com mcherm at gmail.com
Tue Jul 5 14:50:07 EDT 2005


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




More information about the Python-list mailing list