Default attribute values pattern

David Tweet davidtweet at gmail.com
Sat Jan 19 18:02:00 EST 2008


Hello,

Seems to me that setattrs sort of assumes that you want to have all your
initialization arguments set as attributes of the same name.  I would think
you'd sometimes want to be able to process the extra arguments inside of each
__init__, assign them to attributes with different names, etc.

My approach would be to treat each __init__ as a wrapping function, grabbing
the items it needs out of the keyword dictionary and then calling the next
__init__.  Curious to hear other approaches though:


def Grab(argdict, key, default):
  """Like argdict.get(key, default), but also deletes key from argdict."""
  if key in argdict:
    retval = argdict["key"]
    del(argdict[key])
  else:
    retval = default
  return retval


class Base(object):
  def __init__(self, x=0, y=None):
    print "in Base init"
    self.x = x
    self.y = y


class Derived1(Base):
  def __init__(self, **kwargs):
    print "in Derived1 init"
    self.z = Grab(kwargs, "z", None)
    super(Derived1, self).__init__(**kwargs)


class Derived2(Derived1):
  def __init__(self, **kwargs):
    print "in Derived2 init"
    self.a = Grab(kwargs, "a", 0)
    self.b = Grab(kwargs, "b", False)
    super(Derived2, self).__init__(**kwargs)
    print self.__dict__


newthing = Derived2(x=234, y="blah", a=55555)


On Jan 19, 2008 10:14 AM, George Sakkis <george.sakkis at gmail.com> wrote:
> A situation that often comes up is having to initialize several
> instance attributes that accept a default value. For a single class,
> passing the default values in __init__ is fine:
>
>     class Base(object):
>         def __init__(self, x=0, y=None):
>             self.x = x
>             self.y = y
>
> For inherited classes that need to override __init__ while keeping a
> compatible interface though, the default values have to be repeated:
>
>     class Derived(Base):
>         def __init__(self, x=0, y=None, z=''):
>             super(Derived,self).__init__(self,x,y)
>             self.z = ''
>
> For just two attributes and two classes that's maybe not too bad but
> for many attributes and/or derived classes that may span multiple
> modules, that doesn't seem to scale from a maintenance point of view,
> especially if the defaults change over time.
>
> A pattern I've been using lately instead is store the defaults in
> class attributes and let __init__ accept keyword arguments:
>
>     class Base(object):
>
>         x = 0
>         y = None
>
>         def __init__(self, **kwds):
>             setattrs(self, kwds)
>
> where setattrs is:
>
>     def setattrs(self, attrvals, strict=True):
>         if strict:
>             # raise AttributeError if some attr doesn't exist already
>             for attr in attrvals.iterkeys():
>                 getattr(self,attr)
>         for attr,val in attrvals.iteritems():
>             setattr(self, attr, val)
>
> This way, only the new and overriden default attributes have to
> repeated in derived classes:
>
>     class Derived(Base):
>
>         x = 1
>         z = ''
>
>         def __init__(self, **kwds):
>             super(Derived,self).__init__(**kwds)
>             print 'In Derived.__init__'
>
>
> Is this a good way of doing it ? Is there a better pattern ?
>
> George
> --
> http://mail.python.org/mailman/listinfo/python-list
>



-- 
-David



More information about the Python-list mailing list