[Tutor] Clueless
Gonçalo Rodrigues
op73418 at mail.telepac.pt
Sun Mar 14 15:37:54 EST 2004
Em Sat, 13 Mar 2004 17:44:15 -0800 (PST), Marilyn Davis
<marilyn at deliberate.com> fed this fish to the penguins:
>
>I can't even give this one a good subject line, I'm so clueless.
>
>I'm trying to make something meaningful using __getattribute__.
>What a bear to stop all the infinite loops!
>
>But, finally, I have all that under control.
>
>So, my classes are:
>
> Logger object
> /|\ /|\ /|\
> | | |
> Watched -------------------- |
> /|\ list
> | /|\
> | |
> WatchedList ---------------------
>
>All is cool as long as I don't implement Logger.__del__
>
>But if I do, crash-city when an object goes away:
>
>Exception exceptions.AttributeError: "'NoneType' object has no
>attribute 'close'" in <bound method WatchedList.__del__ of []> ignored
>
>If anyone has time and inclination, could you help?
I do not know what is the problem, so I suggest you post to
comp.lang.py if no one elese can help. Still there are a few glitches
with your code -- see below.
>
>Thank you so much.
>
>Marilyn Davis
>
>#!/usr/bin/env python2.2
>'''New style classes have __getattribute__ which intercept
>all references to attributes, ones that exist and don't
>exist. We'll make a Watched class that logs all accesses and
>assignments.'''
>
>import time
>
>class Logger:
> def __init__(self, name):
> self.file = open(name, 'w')
> def logit(self, entry):
> self.file.write(time.ctime(time.time()))
> self.file.write('\n' + entry + '\n')
> self.file.flush()
># def __del__(self):
># self.file.close()
>
Python calls __del__ the object is about to be destroyed (it's
refcount is 0). There are problems when the object participates in a
cycle - in that case Python's garbage collector refuses to dispose of
the cycle because of the existence of __del__.
All told, this means in practice that __del__ is almost always a bad
choice for managing external resources. Just free them explicitely --
that is, call close when you're done with the resource.
>class Watched(object, Logger):
> def __init__(self, log_name):
> self.log = Logger(log_name + '.log')
>
> def __getattribute__(self, attrname):
># print 'getattribute called on', attrname
> ret = object.__getattribute__(self, attrname)
> if attrname != 'log' and attrname[:2] != '__':
> self.log.logit(attrname + ' accessed, value = ' + str(ret))
> return ret
>
> def __getattr__(self, attrname):
> '''Called when attrname is not in __dict__ already.'''
> if attrname != 'log' and attrname[:2] != '__':
> self.log.logit('Attempt to access ' + attrname + ' which does not exist.')
> self.__dict__[attrname] = None
> return None
>
__getattr__ will *never* be called so this is not needed. Recall:
__getattribute__ gets called on *every* attribute lookup, so it
*always* overrides __getattr__. This means that, even for
self.__dict__
__getattribute__ is called! It is a very tricky method, easy to get
into infinite loops.
I don't have anything else to point right now, I'm out of time but
I'll still try to have a look at the code later and see if anything is
wrong. If I find out anything I'll post here on the list.
With my best regards,
G. Rodrigues
More information about the Tutor
mailing list