Conflicting needs for __init__ method
fumanchu
fumanchu at amor.org
Mon Jan 15 19:02:03 EST 2007
Steven D'Aprano wrote:
> > class Rational(object):
> > def __init__(self, numerator, denominator):
> > print "lots of heavy processing here..."
> > # processing ints, floats, strings, special case arguments,
> > # blah blah blah...
> > self.numerator = numerator
> > self.denominator = denominator
> > def __copy__(self):
> > cls = self.__class__
> > obj = cls.__new__(cls)
> > obj.numerator = self.numerator
> > obj.denominator = self.denominator
> > return obj
> > def __neg__(self):
> > obj = self.__copy__()
> > obj.numerator *= -1
> > return obj
>
>
> Here's a variation on that which is perhaps better suited for objects with
> lots of attributes:
>
> def __copy__(self):
> cls = self.__class__
> obj = cls.__new__(cls)
> obj.__dict__.update(self.__dict__) # copy everything quickly
> return obj
I recently had to do something similar for my ORM, where a
user-instantiated object gets expensive default values, but the back
end just overwrites those defaults when "resurrecting" objects, so it
shouldn't pay the price. However (and this is the tricky part), I also
wanted to allow subclasses to extend the __init__ method, so just using
cls.__new__(cls) didn't quite go far enough. Here's what I ended up
with [1]:
def __init__(self, **kwargs):
self.sandbox = None
cls = self.__class__
if self._zombie:
# This is pretty tricky, and deserves some detailed
explanation.
# When normal code creates an instance of this class, then
the
# expensive setting of defaults below is performed
automatically.
# However, when a DB recalls a Unit, we have its entire
properties
# dict already and should skip defaults in the interest of
speed.
# Therefore, a DB which recalls a Unit can write:
# unit = UnitSubClass.__new__(UnitSubClass)
# unit._zombie = True
# unit.__init__()
# unit._properties = {...}
# instead of:
# unit = UnitSubClass()
# unit._properties = {...}
# If done this way, the caller must make CERTAIN that all
of
# the values in _properties are set, and must call
cleanse().
self._properties = dict.fromkeys(cls.properties, None)
else:
# Copy the class properties into self._properties,
# setting each value to the UnitProperty.default.
self._properties = dict([(k, getattr(cls, k).default)
for k in cls.properties])
# Make sure we cleanse before assigning properties from
kwargs,
# or the new unit won't get saved if there are no further
changes.
self.cleanse()
for k, v in kwargs.iteritems():
setattr(self, k, v)
The _zombie argument is therefore a flag which allows you to keep the
initialization code inside __init__ (rather than repeating it inside
every method).
Robert Brewer
System Architect
Amor Ministries
fumanchu at amor.org
[1] http://projects.amor.org/dejavu/browser/trunk/units.py#l552
More information about the Python-list
mailing list