[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