__getattr__ weirdness

G

Greg Brunet

In adding the ability to refer to field values using dbfFile.field
notation, I learned how to use __getattr__ and __setattr__ . After some
trial and error, I got it working. But as part of my trials, I added
some print statements to debug stuff. The ones I added to __setattr__
work as expected, but the one in __getattr__ seems to get called just
under 1000 times for every __getattr__ call!

Something is obviously not right here - but I'm at a loss to understand
what's going on. I've pared down my code to still show it happening &
included it below. If you run this program & pipe the output to a file,
you'll get just under 14000 debug lines. Any ideas? Thanks!

--
Greg


# ----------------------------------------------------------------------
----------
class test:
"""Introspection test"""

#----------------------------------------
def __init__(self,filename):
print '** __init__'
self._filename=filename
self._del=' '
self._dirty=False
self._open=False
self._rec=[]
self._recno = 1

#----------------------------------------
def __getattr__(self, key):
""" Return DBF record values by field name """
print "_ga: " + key
try:
return self._rec[self._fldNames.index(key.upper())]
except:
raise AttributeError("Unknown Field: %s" % ( key ))

#----------------------------------------
def __setattr__(self, key, val):
""" Update DBF record values by field name """
print "_sa: %s: %s" % (key, val)
try:
self._rec[self._fldNames.index(key.upper())] = val
print " (DBF field assignment)"
except:
self.__dict__[key] = val # use the regular variable!
#raise AttributeError("Unknown Field: %s" % ( key ))

#----------------------------------------
#----------------------------------------
if __name__ == "__main__":

f = test('test.dbf')
f._del='*'
f._recno=123
f._recno=1
f._recno=2
f._recno=3
f._recno=4
f._recno=5
f._recno=6
 
G

Greg Brunet

I've figured out one thing: that be re-arranging the __init__ code
assignments (and adding one that was placed later in code I snipped
out), I am able to get the extra _ga calls to stop a lot earlier. This
code:

#----------------------------------------
def __init__(self,filename):
print '** __init__'
self._rec=[]
self._fldNames=[]
self._filename=filename
self._del=' '
self._dirty=False
self._open=False
self._recno = 1

.... by assigning _rec & _fldNames first, gets the repeated _ga calls to
stop after the first assignment following those two assignments. I'm
still at a loss as to why _ga is being called all these times to begin
with though! I'm only assigning values, not requesting them! Thanks,
 
S

Stephan Diehl

Greg said:
In adding the ability to refer to field values using dbfFile.field
notation, I learned how to use __getattr__ and __setattr__ . After some
trial and error, I got it working. But as part of my trials, I added
some print statements to debug stuff. The ones I added to __setattr__
work as expected, but the one in __getattr__ seems to get called just
under 1000 times for every __getattr__ call!

Something is obviously not right here - but I'm at a loss to understand
what's going on. I've pared down my code to still show it happening &
included it below. If you run this program & pipe the output to a file,
you'll get just under 14000 debug lines. Any ideas? Thanks!

Within the __getattr__ method, you can't just do normal attribute access as
this will trigger another call to __getattr__, so you where stuck in an
infinite loop.
try to access the required attribute directly from the __dict__

def __getattr__(self, key):
""" Return DBF record values by field name """
print "_ga: " + key
try:
# return self._rec[self._fldNames.index(key.upper())]
^^^^
return self.__dict__['_rec'][self._fldNames.index(key.upper())]
except:
raise AttributeError("Unknown Field: %s" % ( key ))

Hope that helps

Stephan
 
G

Greg Brunet

Stephan Diehl said:
Within the __getattr__ method, you can't just do normal attribute access as
this will trigger another call to __getattr__, so you where stuck in an
infinite loop.
try to access the required attribute directly from the __dict__

def __getattr__(self, key):
""" Return DBF record values by field name """
print "_ga: " + key
try:
# return self._rec[self._fldNames.index(key.upper())]
^^^^
return self.__dict__['_rec'][self._fldNames.index(key.upper())]
except:
raise AttributeError("Unknown Field: %s" % ( key ))

Hope that helps

Stephan

Hey Stephan:

That did the trick! Actually, I had to do the same for self._fldNames
as well. Also, I changed them in the _sa code section instead of the
_ga code, since now that I look at it again with a little better
understanding, the original _sa code was referring to the _rec &
_fldNames variables/attributes directly, so as long as they weren't
defined, it was triggering the _ga calls. So now the _ga code doesn't
get called unless I specifically ask for it - like I would want. The
code now looks like:

#----------------------------------------
def __getattr__(self, key):
""" Return DBF record values by field name """
print "_ga: " + key
try:
return self._rec[self._fldNames.index(key.upper())]
except:
raise AttributeError("Unknown Field: %s" % ( key ))

#----------------------------------------
def __setattr__(self, key, val):
""" Update DBF record values by field name """
print "_sa: %s: %s" % (key, val)
try:

self.__dict__['_rec'][self.__dict__['_fldNames'].index(key.upper())] =
val
print " (DBF field assignment)"
except:
self.__dict__[key] = val # use the regular variable!
#raise AttributeError("Unknown Field: %s" % ( key ))

Thanks for everyone's help!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top