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