This post originated from an RSS feed registered with Python Buzz
by Ben Last.
Original Post: __init__ Considered Harmful
Feed Title: The Law Of Unintended Consequences
Feed URL: http://benlast.livejournal.com/data/rss
Feed Description: The Law Of Unintended Consequences
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.