using __getitem()__ correctly

Charles T. Smith cts.private.yahoo at gmail.com
Wed Dec 30 11:58:36 EST 2015


On Wed, 30 Dec 2015 08:35:57 -0700, Ian Kelly wrote:

> On Dec 30, 2015 7:46 AM, "Charles T. Smith"
> <cts.private.yahoo at gmail.com> wrote:
>> As is so often the case, in composing my answer to your question, I
>> discovered a number of problems in my class (e.g. I was calling
>> __getitem__() myself!), but I'm puzzled now how to proceed.  I thought
>> the way you avoid triggering __getattr__() from within that was to use
>> self.__dict__[name] but that doesn't work:
>>
>>   (PDB)p self.attrs.keys()
>>   ['mcc', 'abc']
>>   (PDB)p self.attrs.__dict__['abc']
>>   *** KeyError: KeyError('abc',)
> 
> What leads you to believe that this is triggering a call to __getattr__?
> The KeyError probably just means that the key 'abc' wasn't found in the
> dict.


I meant, it doesn't work because I'm not getting at the attribute  Although keys()
sees it, it's not in the __dict__ attribute of attrs.  If it's not there, where is it?


>             print "attrdict:av:__getattr__: autovivifying ", name
>             #self.__dict__.__setitem__ (name, self.__class__())
>             #self.__setitem__ (name, self.__class__()) self.__setattr__
>             (name, self.__class__())
> 
> No reason to explicitly call __setitem__ or __setattr__ here. I'd
> probably just do self[name] = self.__class__()


The reason I used this is to avoid trigging the __setitem__() method:

  self.__setattr__(name, self.__class__())

which is invoked if I use the "self[name]" syntax.  But that didn't work.

Is it just impossible to get at attributes without going through either
__getattr__() or __getitem__()?



> Based on the preceding, you probably want to return the value you just
> set in the dict, correct? So just return self[name].


The problem is that then triggers the __getitem__() method and I don't
know how to get to the attributes without triggering __getattr__().

It's the interplay of the two that's killing me.

In the example, if I have:

  self.mcc = self.attrs.mcc


The crux:

Then __getattr__() triggers for the mcc.  If I try to use self.attrs['mcc']
to get it, then that triggers __getitem__().  Okay, if the key is not an int,
I'll go and get it and return it... unfortunately that triggers __getattr__(),
an infinite loop.

I tried using:

    attrdict.__getattr__ (self, 'mcc')

but that didn't help, of course.  I also tried so, but I've got this wrong, somehow:

    super (attrdict, self).__getattr__ ('mcc')






class attrdict(dict):
    def __init__ (self, name = None):
        if name:
            self.update (name)
        print "attrdict: instantiated: ", name
        
    # AutoVivification
    def __getattr__ (self, name):
        print "attrdict:av:__getattr__: entered for ", name
        if name not in self.keys():
            print "attrdict:av:__getattr__: autovivifying ", name
            self[name] = self.__class__()
        return self[name]

    def __getitem__ (self, key):
        print "attrdict:av:__getitem__: entered for ", key
        if type (key) is int:          # TODO: support slices
            return self.__getitem__(key)
        return attrdict.__getattr__(self, key)

    def __setattr__(self, name, value):
        self[name] = value



More information about the Python-list mailing list