Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #101010

Re: using __getitem()__ correctly

From Ian Kelly <ian.g.kelly@gmail.com>
Newsgroups comp.lang.python
Subject Re: using __getitem()__ correctly
Date 2015-12-30 13:40 -0700
Message-ID <mailman.83.1451508086.11925.python-list@python.org> (permalink)
References <n60kcc$h89$1@dont-email.me> <mailman.70.1451481087.11925.python-list@python.org> <n60qcp$rtp$2@dont-email.me> <mailman.76.1451489799.11925.python-list@python.org> <n612fj$rtp$4@dont-email.me>

Show all headers | View raw


On Wed, Dec 30, 2015 at 9:58 AM, Charles T. Smith
<cts.private.yahoo@gmail.com> wrote:
> 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@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?

I think you're probably getting confused because there are three
different dicts at play here:

* Since your attrdict class inherits from dict, self.attrs is a dict.
* self.attrs.__dict__ is a *different* dict, used to store the
instance attributes of self.attrs.
* self.attrs.__class__.__dict__  is another different dict, used to
store the class attributes of attrdict.

The keys method that you're calling above is a method of the
self.attrs dict, which is where your attrdict's __setattr__ is setting
it. That's why you find it there but not in self.attrs.__dict__.

>>             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.

But the body of your __setattr__ method is just "self[name] =
self.__class__()", which is the exact same code as what I suggested
and will still invoke __setitem__.

That said, I don't get why you're trying to avoid calling __setitem__.
If you're trying to store the attribute as a dict item, as you seem to
be doing, why shouldn't that dict's __setitem__ be involved?

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

No.

>> 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.

The only interplay of the two is what you have written into your class.

> 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.

How precisely are you trying to store these: as an attribute, or as a
dict item? If it's supposed to be in the dict, then why is your
__getitem__ trying to look up an attribute to begin with?

> 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)

Here the method as written is just going to end up calling itself. You
probably want super(attrdict, self).__getitem__(key)

>         return attrdict.__getattr__(self, key)

And here if you really want to access the instance attributes without
using __getattr__, just use self.__dict__[key].

I don't understand what it is that you're trying to accomplish here by
looking the key up in the instance attributes, though. It looks very
circular. I think you should clearly define where you expect the items
to be stored and then only check that location.

Back to comp.lang.python | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

using __getitem()__ correctly "Charles T. Smith" <cts.private.yahoo@gmail.com> - 2015-12-30 12:57 +0000
  Re: using __getitem()__ correctly Chris Angelico <rosuav@gmail.com> - 2015-12-31 00:11 +1100
    Re: using __getitem()__ correctly "Charles T. Smith" <cts.private.yahoo@gmail.com> - 2015-12-30 14:40 +0000
      Re: using __getitem()__ correctly Ian Kelly <ian.g.kelly@gmail.com> - 2015-12-30 08:35 -0700
        Re: using __getitem()__ correctly "Charles T. Smith" <cts.private.yahoo@gmail.com> - 2015-12-30 16:58 +0000
          Re: using __getitem()__ correctly Ian Kelly <ian.g.kelly@gmail.com> - 2015-12-30 13:40 -0700
            Re: using __getitem()__ correctly "Charles T. Smith" <cts.private.yahoo@gmail.com> - 2015-12-30 22:54 +0000
              Re: using __getitem()__ correctly "Charles T. Smith" <cts.private.yahoo@gmail.com> - 2015-12-30 22:58 +0000
              Re: using __getitem()__ correctly Ben Finney <ben+python@benfinney.id.au> - 2015-12-31 10:13 +1100
                Re: using __getitem()__ correctly "Charles T. Smith" <cts.private.yahoo@gmail.com> - 2015-12-30 23:18 +0000
                Re: using __getitem()__ correctly Steven D'Aprano <steve@pearwood.info> - 2015-12-31 10:50 +1100
                Re: using __getitem()__ correctly Ben Finney <ben+python@benfinney.id.au> - 2015-12-31 11:21 +1100
                Re: using __getitem()__ correctly "Charles T. Smith" <cts.private.yahoo@gmail.com> - 2015-12-31 11:30 +0000
                Re: using __getitem()__ correctly Ben Finney <ben+python@benfinney.id.au> - 2015-12-31 22:51 +1100
                Re: using __getitem()__ correctly Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2015-12-31 12:12 +0000
                Re: using __getitem()__ correctly "Charles T. Smith" <cts.private.yahoo@gmail.com> - 2015-12-31 13:39 +0000
                Re: using __getitem()__ correctly Steven D'Aprano <steve@pearwood.info> - 2016-01-01 02:03 +1100
                Re: using __getitem()__ correctly "Charles T. Smith" <cts.private.yahoo@gmail.com> - 2015-12-31 11:17 +0000
                Re: using __getitem()__ correctly Steven D'Aprano <steve@pearwood.info> - 2016-01-01 01:43 +1100
              Re: using __getitem()__ correctly Ian Kelly <ian.g.kelly@gmail.com> - 2015-12-30 17:31 -0700
                Re: using __getitem()__ correctly "Charles T. Smith" <cts.private.yahoo@gmail.com> - 2015-12-31 12:45 +0000

csiph-web