__getattr__ and __setattr__ troubles

Adam Ruth aruth at intercation.com
Wed May 24 10:15:33 EDT 2000


Here's your problem:

>   def setFieldValue(self, field, value):
>     print "Call: setFieldValue", field, value
>     if self._tblDef.has_key(field):
>       self._fields[field]=value
>     else:
>       self.__dict__[field]=value

Since _tblDef doesn't have a "field3", then field3 will be set in
the __dict__, not in the _fields as you might expect.

The __str__ and __coerce__, etc, will all be sent to
__getattr__ because they are *not* defined in the
class.  If they were, then __getattr__ would never be
called.

You'll notice that on the print "3", myrec.field3 call, that
__getattr__ is never called, that's because setFieldValue
put it in __dict__.

Hope this helps.

--
Adam Ruth
InterCation, Inc.
www.intercation.com


"Boudewijn Rempt" <boud at rempt.xs4all.nl> wrote in message
news:8gehq1$kq6$1 at news1.xs4all.nl...
> I'm playing with a kind of generic record class that should keep
> a dictionary of fields and values besides a lot of housekeeping
> stuff. I want the fields also to be available using record.field
> notation.
>
> I thought I'd use __getattr__ and __setattr__ for it, but I was quite
> surprised by the results, and I really hope someone can put me right!
>
> From the documentation I understood that __getattr__ is only called when
> the ordinary normal mechanism fails. However, I see it being called even
> when my app needs things like __cmp__ and __repr__. though not for the
> fields I added myself after creating the object.
>
> This is my script:
>
> #!/usr/bin/env python
> class dbRecord:
>
>   def __init__(self, tblDef, fields={}):
>     self._tblDef=tblDef
>     self._fields=fields
>
>   def __getattr__(self, name):
>     print "Call: __getattr__", name
>     if self.__dict__.has_key("_fields"):
>       return self.getFieldValue(name)
>     else:
>       return self.__dict__[name]
>
>   def __setattr__(self, name, value):
>     print "Call: __setattr__", name, value
>     if self.__dict__.has_key("_fields"):
>       self.setFieldValue(name, value)
>     else:
>       self.__dict__[name]=value
>
>   def getFieldValue(self, field):
>     """
>       return the value of a field in the record.
>     """
>     print "Call: getFieldValue", field
>     if self._fields.has_key(field):
>       return self._fields[field]
>     else:
>       if self._tblDef.has_key(field):
>         self._fields[field]=None
>         return None
>       else:
>         return self.__dict__[field]
>
>   def setFieldValue(self, field, value):
>     print "Call: setFieldValue", field, value
>     if self._tblDef.has_key(field):
>       self._fields[field]=value
>     else:
>       self.__dict__[field]=value
>
>   def getFields(self):
>     return self._fields
>
> def main():
>   tblDef={"field1": "aField", "field2": "anotherField"}
>   fields={"field1": "contents"}
>   myrec=dbRecord(tblDef, fields)
>   myrec.field2="aaa"
>   myrec.field3="bbb"
>   print "1", myrec.field1
>   print "2", myrec.field2
>   print "3", myrec.field3
>   for fieldname, value in myrec.getFields().items():
>     print fieldname, value
>   print "myrec:", myrec
>   myrec2=dbRecord(tblDef, fields)
>   if myrec==myrec2:
>     print "same"
>   else:
>     print "different"
>
>
> if __name__=="__main__":
>   main()
>
> And this is the suprising output:
>
> bash-2.03$ dbobj.py
> Call: __setattr__ _tblDef {'field1': 'aField', 'field2':
> 'anotherField'}
> Call: __setattr__ _fields {'field1': 'contents'}
> Call: __setattr__ field2 aaa
> Call: setFieldValue field2 aaa
> Call: __setattr__ field3 bbb
> Call: setFieldValue field3 bbb
> 1 Call: __getattr__ field1
> Call: getFieldValue field1
> contents
> 2 Call: __getattr__ field2
> Call: getFieldValue field2
> aaa
> 3 bbb
> field1 contents
> field2 aaa
> myrec:  Call: __getattr__ __str__
> Call: getFieldValue __str__
> Call: __getattr__ __repr__
> Call: getFieldValue __repr__
> <__main__.dbRecord instance at 80e9170>
> Call: __setattr__ _tblDef {'field1': 'aField', 'field2':
> 'anotherField'}
> Call: __setattr__ _fields {'field1': 'contents', 'field2': 'aaa'}
> Call: __getattr__ __coerce__
> Call: getFieldValue __coerce__
> Call: __getattr__ __cmp__
> Call: getFieldValue __cmp__
> Traceback (innermost last):
>   File "./dbobj.py", line 66, in ?
>     main()
>   File "./dbobj.py", line 59, in main
>     if myrec==myrec2:
>   File "./dbobj.py", line 11, in __getattr__
>     return self.getFieldValue(name)
>   File "./dbobj.py", line 34, in getFieldValue
>     return self.__dict__[field]
> KeyError: __cmp__
>
> I hope the solution is fairly simple and that I've only misread
> something ;-).
>
> --
>
> Boudewijn Rempt  | http://www.valdyas.org





More information about the Python-list mailing list