__init__ Considered Harmful

Of course, I don’t really think __init__ is harmful, but why let logic stand in the way of a good title?

On the other hand, there are times when one would like objects that don’t need to be explicitly initialized; the need to remember to invoke all the appropriate __init__ methods for all superclasses in an appropriate order is a source of error, in that I forget, from time to time.  Hey, I’m only human.  Python’s dynamic nature means that we can write objects that only set up their values if any of their methods are actually called.  Useful for mixin classes that provide some functionality that may or may not be used.

Here’s such a class:

class Snapshottable(object):
    """When mixed into an object, provides a way to snapshot the value of some
    or all alltributes into a log.  The log is only created if at least one snapshot is taken."""

    def snapshot(self, attributes=None, note=None):         """Record the str() values of all attributes in the         log (or the contents of the object's __dict__ if         attributes is None.  If note is passed, prepend to         the log entry."""         if not attributes:             attributes = [x for x in self.__dict__.keys() if not x.startswith('__')]

        if note:             logentry=note+'\n'         else:             logentry=''         for a in attributes:             if hasattr(self, a):                 logentry += "%s=%s\n" % (a,getattr(self,a))         try:             self.log.append(logentry)         except AttributeError:             self.log = [logentry]

                def getlog(self):         try:             return self.log         except AttributeError:             self.log = []             return self.log

    def clearlog(self):         self.log = []

There is no __init__.  A call to snapshot(), getlog() or clearlog() will create the log as needed.  Rather than test for the presence of the log attribute on entry to any method (which is less efficient), we let access to it throw an exception.  Nothing profound, but it’s an interesting idea.

Self-initialising objects can create only as much state as they need to, on demand; thus more complex examples may need to deal with being partially initialised.  There comes a point (and I’d say it’s earlier rather than later) when it becomes more straightforward to have a proper initialisation so that one can be more sure of always having a consistent state.

4 thoughts on “__init__ Considered Harmful

  1. re: __init__ considered harmful

    What’s wrong with just defining __new__ properly in metaclass and just inherit from that ??

    • Re: __init__ considered harmful

      Nothing wrong with that at all. This is a different way to think about the idea; not worse, not better, just different. Thinking about different ways to do things is fun and a good way to learn 🙂

      Although I’d argue this is a simpler way to express the same general idea; some people get scared by metaclasses…

      regards
      ben

  2. Actually a metaclass is *not* required, as long as you specify the attribute name, as in your example here. But you’ve basically given the gist of the idea here. PEAK’s bindings mainly add polish: thread safety, recursion protection, support for binding class attributes as well as instance attributes, etc.

    –PJE

  3. BasicProperty’s properties have a similar effect…

    BasicProperty provides a similar effect (initialise-only-on-demand) through use of fairly involved descriptor objects. There is an __init__ in the propertied class which basically allows for named-argument passing to assign property values on initialisation.

    class BaseWatcher( propertied.Propertied ):
    “””Base class for watching objects”””
    object_id = common.LongProperty(
    “object_id”, “””NetworkObject this object watches”””,
    setDefaultOnGet = 0,
    defaultFunction = lambda prop,client: client.objectRecord.object_id,
    )
    objectRecord = basic.BasicProperty(
    “objectRecord”, “””Storage for the object record we represent”””,
    )
    children = common.DictionaryProperty(
    “children”, “””Children of this record”””,
    )
    offlineTolerance = common.FloatProperty(
    “offlineTolerance”, “””Tolerance fraction for offline subset”””,
    defaultValue= .9,
    )

    c = BaseWatcher( )
    c.children[ ‘this’ ] = ‘that’ # children dictionary is created here

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s