[Tutor] set/getattr and inheritance

Kirby Urner urnerk@qwest.net
Fri, 05 Oct 2001 14:16:07 -0700


>
>Is there anyway to use these setattr/getattr pair
>yet still be able to access ancestor's variables ?
>
>thx in advance.
>
>pan


A couple things:

In creating 'vars' to store object attributes, and putting
this in __dict__, you're somewhat redundantly duplicating
the purpose of __dict__ itself, which is to keep the kind
of info you're sticking in vars.  So instead of:

  class c_myclass(c_template):

     def __init__(self):
        self.__dict__['vars']={}
         self.vars['myName']='pan'

you could just go:

       def __init__(self):
          self.__dict__['myName'] ='pan'

Then your __setattr__ method could check __dict__
directly:

       def __setattr__(self,name,value):
         if not self.__dict__.has_key(name):
             raise AttributeError
         self.__dict__[name]=value

As a previous respondant pointed out, __getattr__ is
invoked only if there's an attribute error, giving
you some alternative way of handling the problem.
To simply raise an attribute error in __getattr__
is unnecessary -- that's what Python would do for
you anyway.

Note that Python has no problem finding the base class
attributes, and so doesn't invoke even touch your
__getattr__ when you ask for mc.myAddr.  It simply
returns 'blahblahblah'.

This might not be a problem, since "data validation" is
something you'd do with __setattr__ but not __getattr__,
i.e. to read a value already stored in the object
shouldn't involve any validation.

As for making your subclassed selves aware of base
class attributes, you could update the instance dictionary
with the name:value paires of the base class.  If there's
only one, you could do something like:

   def __init__(self):
      self.__dict__['myName'] ='pan'
      self.__dict__.update(self.__class__.__bases__[0].__dict__)

This would let you change the local copy of myAddr, without
affecting the baseclass value.  New objects, instanced from
c_myclass, would start with 'blahblahblah', even if mc had
its own unique new value.  Furthermore, changes at the base
class level would not propagate to the instances, as in this
scenario each was initialized with a local snapshot of the
ancestor variables.

If your goal is to make assignments to inherited properties
trigger changes at the base class level, then I worry about
the convoluted nature of this scheme.  If you want some
data validation at the ancestor class level, then why not
put validations in the ancestor and inherit them?

Also, I'm wondering if you are clear on the difference
between class variables and instance variables.  If the
goal is to use the base class to initialize a bunch of
default values, then why not move these initializations
to the subclass as class variables and get rid of them
in base class?  For example, you could go:

  >>> class c_myclass:

        myAddr = 'blahblahblah'

        def __init__(self):
          self.__dict__['myName'] ='pan'
          self.__dict__['myAddr'] = c_myclass.myAddr

       def __setattr__(self,name,value):
          if not self.__dict__.has_key(name):
              raise AttributeError
          self.__dict__[name]=value


  >>> mc = c_myclass()
  >>> mc.myAddr
  'blahblahblah'
  >>> mc.myAddr = 'duh'
  >>> mc.myAddr
  'duh'
  >>> mc.myName = 'pan'
  >>> newmc = c_myclass()
  >>> newmc.myAddr
  'blahblahblah'

And so on.

Kirby


Kirby