Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #101052
| From | Oscar Benjamin <oscar.j.benjamin@gmail.com> |
|---|---|
| Newsgroups | comp.lang.python |
| Subject | Re: using __getitem()__ correctly |
| Date | 2015-12-31 12:12 +0000 |
| Message-ID | <mailman.106.1451563991.11925.python-list@python.org> (permalink) |
| References | (6 earlier) <n61nbh$rtp$5@dont-email.me> <mailman.92.1451517241.11925.python-list@python.org> <56846ddf$0$1601$c3e8da3$5496439d@news.astraweb.com> <mailman.93.1451521331.11925.python-list@python.org> <n633kb$gli$3@dont-email.me> |
On 31 December 2015 at 11:30, Charles T. Smith
<cts.private.yahoo@gmail.com> wrote:
>>> Obviously there is a syntax difference between x.attr and x['key']
>>
>> Not merely syntax; the attributes of an object are not generally
>> available as items of the container.
>
>
> What are the set of ways that an attribute is accessible? Including
> implementation implications?
>
>
>>
>>> Either the instance __dict__, the class __dict__, or a superclass
>>> __dict__.
>>
>> No, I'm not referring to the ‘__dict__’ attribute of an object; I'm
>> referring to the object itself.
>>
>> To talk about the attributes of an object ‘foo’ is distinct from talking
>> about the items in a dictionary ‘foo’. That distinction is real, and
>> important.
>
>
> But wanting to deal with the attributes of an object without considering
> the way it's implemented - although possible - requires a complete virtual
> model that covers all implications. It's easier to simply understand how the
> objects work under the covers.
When you write x.attr the name 'attr' is looked up on the object x.
This calls x.__getattribute__('attr'). In turn this checks the dict
associated with the object x i.e. x.__dict__['attr']. This in turn
calls x.__dict__.__getitem__('attr'). The lookup of x.__dict__ is
special and doesn't use the normal __getattribute__ mechanism
(otherwise this would be an infinite recursion). Generally special
attributes (with double underscores) are looked up in a different way.
If x.__dict__ does not have the attribute then the dict associated
with the class/type of x is checked i.e. x.__class__.__dict__['attr'].
The lookup of x.__class__ is also special. Failing this the other
classes in x.__class__.__mro__ are checked i.e.
x.__class__.__mro__[1].__dict__['attr']. Once these are exhausted
x.__getattribute__('attr') falls back on calling
x.__getattr__('attr').
IIUC you're trying to create an attribute dict where the same
attributes can be looked up via x.attr or x['attr'] (i.e.
x.__getattribute__('attr') or x.__getitem__('attr')). One way to do
this is to subclass dict and then set each instances __dict__ to be
itself. This way __getattribute__ will search the instance (which is a
dict subclass) as its own attribute dict. You can then use __getattr__
as the fallback for attributes that are not found. A simple
implementation of this could look like:
class attrdict(dict):
def __init__(self, name=None):
self.__dict__ = self
kwargs = {'name':name} if name is not None else {}
super(attrdict, self).__init__(**kwargs)
def __getattr__(self, attrname):
ob = self[attrname] = type(self)(name=attrname)
return ob
>>> d = attrdict('foo')
>>> d
{'name': 'foo'}
>>> d.bar
{'name': 'bar'}
>>> d
{'bar': {'name': 'bar'}, 'name': 'foo'}
The problem with this as with any dict subclass approach is that a
dict has a load of methods (.items() .keys() .pop() ...) that will now
become conflated with your dict keys when you use the attribute
access:
>>> d.items
<built-in method items of attrdict object at 0x7f2025eab868>
This means that you can't use any of the dict method names in whatever
you're doing. This is the reason that a dict uses a different
mechanism __getitem__ so that it can store arbitrary keys at the same
time as having named methods which must be attributes. Personally I
think that the best approach is to ditch the idea of conflating
attributes and keys and just use the subscript x['attr'] syntax.
--
Oscar
Back to comp.lang.python | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll 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