*************** *************** *************** *************** *************** ***
This posting is also available in HTML format:
http://cci.lbl.gov/~rwgk/python/adop...005_07_02.html
*************** *************** *************** *************** *************** ***
Hi fellow Python coders,
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, especially if long variable names are essential for
managing the complexity. Therefore I propose that Python includes
built-in support for reducing the ``self.x=x`` clutter. Below are
arguments for the following approach (*please* don't get too agitated
about the syntax right here, it really is a secondary consideration): :
class grouping:
def __init__(self, .x, .y, .z):
# real code right here
Emulation using existing syntax::
def __init__(self, x, y, z):
self.x = x
del x
self.y = y
del y
self.z = z
del z
Is it really that important?
----------------------------
For applications of non-trivial size, yes. Here is a real-world example
(one of many in that source tree):
http://cvs.sourceforge.net/viewcvs.p...py?view=markup
Fragment from this file::
class manager:
def __init__(self,
crystal_symmetr y=None,
model_indices=N one,
conformer_indic es=None,
site_symmetry_t able=None,
bond_params_tab le=None,
shell_sym_table s=None,
nonbonded_param s=None,
nonbonded_types =None,
nonbonded_funct ion=None,
nonbonded_dista nce_cutoff=None ,
nonbonded_buffe r=1,
angle_proxies=N one,
dihedral_proxie s=None,
chirality_proxi es=None,
planarity_proxi es=None,
plain_pairs_rad ius=None):
self.crystal_sy mmetry = crystal_symmetr y
self.model_indi ces = model_indices
self.conformer_ indices = conformer_indic es
self.site_symme try_table = site_symmetry_t able
self.bond_param s_table = bond_params_tab le
self.shell_sym_ tables = shell_sym_table s
self.nonbonded_ params = nonbonded_param s
self.nonbonded_ types = nonbonded_types
self.nonbonded_ function = nonbonded_funct ion
self.nonbonded_ distance_cutoff = nonbonded_dista nce_cutoff
self.nonbonded_ buffer = nonbonded_buffe r
self.angle_prox ies = angle_proxies
self.dihedral_p roxies = dihedral_proxie s
self.chirality_ proxies = chirality_proxi es
self.planarity_ proxies = planarity_proxi es
self.plain_pair s_radius = plain_pairs_rad ius
# real code, finally
Not exactly what you want to see in a high-level language.
Is there a way out with Python as-is?
-------------------------------------
Yes. If you take the time to look at the file in the CVS you'll find
that I was cheating a bit. To reduce the terrible clutter above, I am
actually using a simple trick::
adopt_init_args (self, locals())
For completeness, the implementation of ``adopt_init_ar gs()`` is here:
http://cvs.sourceforge.net/viewcvs.p...py?view=markup
While this obviously goes a long way, it has several disadvantages:
- The solution doesn't come with Python -> everybody has to reinvent.
- 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_ar gs`` (since everybody has a local version/variety).
- The ``adopt_init_ar gs(self, locals())`` incantation is hard to
remember and difficult to explain to new-comers.
- 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).
- In some cases the ``adopt_init_ar gs()`` overhead was found to
introduce a significant performance penalty (in particular the
enhanced version discussed below).
- Remember where Python comes from: it goes back to a teaching
language, enabling mere mortals to embrace programming.
``adopt_init_ar gs(self, locals())`` definitely doesn't live up
to this heritage.
Minimal proposal
----------------
My minimal proposal is to add an enhanced version of ``adopt_init_ar gs()``
as a standard Python built-in function (actual name secondary!)::
class grouping:
def __init__(self, x, y, z):
adopt_init_args ()
# real code
Here is a reference implementation:
http://cvs.sourceforge.net/viewcvs.p....2&view=markup
Implementation of this proposal would remove all the disadvantages
listed above. However, there is another problem not mentioned before:
It is cumbersome to disable adoption of selected variables. E.g.::
class grouping:
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_a gain = but_this_again
# real code, finally
would translate into::
class grouping:
def __init__(self, keep_this, and_this, but_not_this, but_this_again) :
adopt_init_args (exclusions=["but_not_th is"])
# real code
Enhanced syntax proposal
------------------------
The exclusion problem suggests these alternatives::
class grouping:
def __init__(self, self.keep_this, self.and_this, but_not_this,
self.but_this_a gain):
# real code right here
This is conceptually similar to the existing automatic unpacking of tuples.
A shorter alternative (my personal favorite since minimally redundant)::
class grouping:
def __init__(self, .keep_this, .and_this, but_not_this, .but_this_again ):
# real code right here
I guess both versions could be implemented such that users don't incur
a performance penalty compared to the ``self.x=x`` alternative. At the
danger of being overly optimistic: I can imagine that my favorite
alternative will actually be faster (and the fastest).
Enhanced __slot__ semantics proposal
------------------------------------
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_a gain = but_this_again
# real code, finally
Each variable name appears four times! Imagine yourself having to
do this exercise given the real-world example above. Ouch.
Based on the "Enhanced syntax proposal" above I see this potential
improvement::
class grouping:
__slots__ = True
def __init__(self, .keep_this, .and_this, but_not_this, .but_this_again ):
# real code right here
Each variable name appears only once. Phew!
Author: rw**@yahoo.com, July 02, 2005
P.S.: If you reply to this message, please clearly separate
naming/syntax issues from the core issue of providing built-in support
designed to reduce clutter.
_______________ _______________ _______________ _______
Yahoo! Sports
Rekindle the Rivalries. Sign up for Fantasy Football
http://football.fantasysports.yahoo.com