Boston Linux & Unix (BLU) Home | Calendar | Mail Lists | List Archives | Desktop SIG | Hardware Hacking SIG
Wiki | Flickr | PicasaWeb | Video | Maps & Directions | Installfests | Keysignings
Linux Cafe | Meeting Notes | Blog | Linux Links | Bling | About BLU

BLU Discuss list archive


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Python descriptors are not transparent when they're first used



On Mon, 2007-07-30 at 15:46 -0400, Seth Gordon wrote:
> Then I set up a client class like this:
> 
> > class Foo(object):
> >     def __init__(self):
> >         for attr in ('bar', 'baz', 'quux'):
> >             self.__dict__[attr] = WriteOnly(attr)
> > 
> > foo = Foo()
> > foo.bar = 4
> > foo.baz = None
> > print `foo.bar`
> > print `foo.baz`
> > print `foo.quux`
> 
> Running that program (with Python 2.4.4) gives me this output:
> 
> > 4
> > None
> > <WriteOnly.WriteOnly object at 0xf7daa28c>
> 
> Why don't I get "None" on the third line?  What subtle (or
> not-so-subtle) detail of Python descriptors am I missing?

What you've done is to set the attributes Foo.bar, Foo.baz, and Foo.quux
to instances of the WriteOnly class.  However, because Foo.bar is a
reference (just like everything in Python), doing this:

foo.bar = 4

overrides the 'bar' attribute of the instance known as foo.  It is no
longer a 'WriteOnly' instance.  If you did a print str(type(foo.bar)),
it would report that it is now an instance of an Integer object.

Similarly, foo.baz = None is replacing the value of foo.baz (which used
to be a 'WriteOnly' instance) with the None object.

At this point, foo.quux is an instance of a 'WriteOnly' object and
because you're not overriding the __repr__ method, the "'"s are
defaulting to the normal behavior.  

Oh, just as an FYI, I believe the "`" approach is deprecated in
deference to calling repr(whatever).

What I think you're really trying to to do is to override the
__setattr__ and __getattribute__ calls.  Warning, code below is
untested, but I think you want something like this:

class WriteOnly(object):
    def __init__(self, write_only_attrs):
        self.__write_only = {}
        for attr_name in write_only_attrs:
            self.__write_only[attr_name] = 1
        self.__write_once = {}

    def __setitem__(self, key, value):
        if self.__write_only.get(key) and self.__write_once.get(key):
             oldval = self.__write_once.get(key)
             msg = "Can't reset %s from %s to %s" % (key, oldval, value)
             raise Attribute Error, msg
        elif self.__write_only.get(key):
             return self.__write_once[key] = value
        else:
             return self.__dict__[key] = value

    def __getitem__(self, key):
        if self.__write_only.get(key):
                # Note this will throw an exception if you haven't set
                # it yet
		return self.__write_once[key]
        else:
                # Ditto
		return self.__dict__[key]

class Foo(WriteOnly):
    def __init__(self):
        super(Foo, self).__init__(['bar', 'baz', 'quux'])

Feel free to ask questions.

-- 
A: Yes.                                                               
> Q: Are you sure?                                                    
>> A: Because it reverses the logical flow of conversation.           
>>> Q: Why is top posting annoying in email?

Cole Tuininga
colet-KCgK2vT7wad/90uGnh1m2w at public.gmane.org
http://www.code-energy.com/


-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.







BLU is a member of BostonUserGroups
BLU is a member of BostonUserGroups
We also thank MIT for the use of their facilities.

Valid HTML 4.01! Valid CSS!



Boston Linux & Unix / webmaster@blu.org