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

Mike C. Fletcher mcfletch at rogers.com
Sat Jul 2 23:00:34 CEST 2005


Ralf W. Grosse-Kunstleve wrote:
...

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

This can be dealt with quite nicely if you take a step back and consider
what you're trying to do:

    * define a set of properties/fields for a class, potentially with
      default values for any given property
    * define an initialisation function which, given an instance of a
      class with defined properties (potentially with defaults) and a
      mapping of name:value pairs, assigns the named values to the named
      properties...

class Grouping( propertied.Propertied ):
    x = FloatProperty(
       "x", """Holder for the grouping node's x coordinate""",
       defaultValue = 0,
    )
    y = FloatProperty(
       "y", """Holder for the grouping node's y coordinate""",
       defaultValue = 0,
    )
    z = FloatProperty(
       "z", """Holder for the grouping node's z coordinate""",
       defaultValue = 0,
    )
    def __init__( self, **args ):
       # code here to do whatever you like to args (or whatever)...
       super( Grouping, self ).__init__( **args )
       # extra code here...

where the propertied.Propertied class defines a simple init that
iterates through the defined properties pulling those which are present
in the **args of the __init__ function and assigning them to the
appropriate property.

The advantage here is that your class is now documented properly, with
the information about a given property all localised in a definition of
the property.  Your properties can also implement the observer pattern,
automatic type checking and coercion, and can provide default values
that appear when you delete current values (not just during
initialisation).  You can also do useful things like using the defined
properties of a class to auto-generate __repr__ and __str__ values.  You
can have your properties delegate to other objects, or have them delay
loading/resolving a property's value until the last possible second
(lazy loading from an object database, for instance).

The fact that it's all doable in Python 2.2+ without any need for new
syntax... well... that's cool too.

The disadvantage is that the properties tend to be unordered (unless you
explicitly order them, and that's awkward looking), and you have to pass
them to the constructor as keyword arguments.  But then, if you're
defining a class with 50 properties, you likely aren't really wanting to
pass all 50 as positional arguments anyway.

You'll find patterns like this in my own OpenGLContext (3D scenegraph
viewer) and BasicProperty packages, as well as in Traits (originally
part of a 2D graphics package), and Zope's FieldProperty (and PEAK,
though as always with PEAK, it's somewhat weird in there ;) ).  All of
those are largish systems (or used in largish systems), btw.

Just my thoughts,
Mike

-- 
________________________________________________
  Mike C. Fletcher
  Designer, VR Plumber, Coder
  http://www.vrplumber.com
  http://blog.vrplumber.com




More information about the Python-list mailing list